【BZOJ3362】[Usaco2004 Feb]Navigation Nightmare 导航噩梦

Description

    农夫约翰有N(2≤N≤40000)个农场,标号1到N,M(2≤M≤40000)条的不同的垂直或水平的道路连结着农场,道路的长度不超过1000.这些农场的分布就像下面的地图一样,
 
图中农场用F1..F7表示, 每个农场最多能在东西南北四个方向连结4个不同的农场.此外,农场只处在道路的两端.道路不会交叉且每对农场间有且仅有一条路径.邻居鲍伯要约翰来导航,但约翰丢了农场的地图,他只得从电脑的备份中修复了.每一条道路的信息如下:
从农场1往南经距离3到达农场4
从农场1往东经距离13到达农场6
    当约翰重新获得这些数据时,他有时被的鲍伯的问题打断:“农场1到农场2的曼哈顿距离是多少?”所谓在(x1,y1)和(x2,y2)之间的“曼哈顿距离”,就是lx1 - x2|+ly1 - y2|.如果已经有足够的信息,约翰就会回答这样的问题(在上例中答案是23),否则他会诚恳地抱歉并回答-1.

Input

    第1行:两个分开的整数N和M.
    第2到M+1行:每行包括4个分开的内容,F1,F2,L,D分别描述两个农场的编号,道路的长度,F1到F2的方向N,E,S,W.
    第M+2行:一个整数,K(1≤K≤10000),表示问题个数.
    第M+3到M+K+2行:每行表示一个问题,由3部分组成:F1,F2,J.其中Fi和F2表示两个被问及的农场.而J(1≤J≤M)表示问题提出的时刻.J为1时,表示得知信息1但未得知信息2时.

Output

    第1到K行:每行一个整数,回答问题.表示两个农场间的曼哈顿距离.不得而知则输出-1.

Sample Input

7 6
1 6 13 E
6 3 9 E
3 5 7 S
4 1 3 N
2 4 20 W
4 7 2 S
3
1 6 1
1 4 3
2 6 6

Sample Output

13
-1
10

HINT

在时刻1,约翰知道1到6的距离为13;在时刻3,1到4的距离仍然不知道;在时刻6,位置6向北3个距离,向西7个距离于位置2,所以距离为10.

题解:BZOJ题意实在捉鸡,本人强行自编题目描述

题中由于给了所有点间有且只有一条路径,所以就是棵树,即m=n-1

然后看着像个树形DP,但是不能离线,但我们发现点和点之间的关系具有可传递性(即可加性),所以很好地符合了加权并查集的性质。那么我们只需要先按时间排序,然后用双标记的加权并查集来维护就好了

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int n,m;
int f[40010],x[40010],dx[40010],y[40010],dy[40010],rx[40010],ry[40010],ans[40010];
char str[5];
struct QUERY
{
int qa,qb,org,tim;
}q[40010];
bool cmp(QUERY a,QUERY b)
{
return a.tim<b.tim;
}
int find(int a)
{
if(f[a]==a) return a;
int t=f[a];
f[a]=find(f[a]),dx[a]+=dx[t],dy[a]+=dy[t];
return f[a];
}
int z(int a)
{
return a>0?a:-a;
}
int main()
{
scanf("%d%d",&n,&m);
int i,j,a,b;
for(i=1;i<=m;i++)
{
scanf("%d%d%d%s",&x[i],&y[i],&a,str);
if(str[0]=='E') rx[i]=a;
if(str[0]=='W') rx[i]=-a;
if(str[0]=='N') ry[i]=a;
if(str[0]=='S') ry[i]=-a;
}
scanf("%d",&m);
for(i=1;i<=n;i++) f[i]=i;
for(i=1;i<=m;i++) scanf("%d%d%d",&q[i].qa,&q[i].qb,&q[i].tim),q[i].org=i;
sort(q+1,q+m+1,cmp);
for(i=j=1;i<=m;i++)
{
for(;j<=q[i].tim;j++)
{
a=find(x[j]),b=find(y[j]);
f[a]=b,dx[a]=rx[j]+dx[y[j]]-dx[x[j]],dy[a]=ry[j]+dy[y[j]]-dy[x[j]];
}
if(find(q[i].qa)!=find(q[i].qb)) ans[q[i].org]=-1;
else ans[q[i].org]=z(dx[q[i].qa]-dx[q[i].qb])+z(dy[q[i].qa]-dy[q[i].qb]);
}
for(i=1;i<=m;i++) printf("%d\n",ans[i]);
return 0;
}

【BZOJ3363】[Usaco2004 Feb]Cow Marathon 奶牛马拉松

Description

    最近美国过度肥胖非常普遍,农夫约翰为了让他的奶牛多做运动,举办了奶牛马拉松.马拉松路线要尽量长,所以,告诉你农场的地图(该地图的描述与上题一致),请帮助约翰寻找两个最远农场间的距离.

Input

    第1行:两个分开的整数N和M.
    第2到M+1行:每行包括4个分开的内容,Fi,F2,L,D分别描述两个农场的编号,道路的长度,F1到F2的方向N,E,S,W.

Output

    一个整数,表示最远两个衣场间的距离.

Sample Input

7 6
1 6 13 E
6 3 9 E
3 5 7 S
4 1 3 N
2 4 20 W
4 7 2 S

Sample Output

52
最长的马拉松路线从2通过4,1,6,3到5;总长为:20+3+12+9+7=52

题解:求树的直径:先以1为根DFS找出深度最大的点,然后再以这个点为根找出深度最大的,就是直径

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn=40010;
int n,m,cnt,maxx;
int to[maxn<<1],next[maxn<<1],head[maxn],val[maxn<<1],s[maxn];
char str[5];
void add(int a,int b,int c)
{
to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
}
void dfs(int x,int fa)
{
maxx=(s[maxx]<s[x])?x:maxx;
for(int i=head[x];i!=-1;i=next[i]) if(to[i]!=fa) s[to[i]]=s[x]+val[i],dfs(to[i],x);
}
int main()
{
scanf("%d%d",&n,&m);
int i,j,a,b,c;
memset(head,-1,sizeof(head));
for(i=1;i<=m;i++) scanf("%d%d%d%s",&a,&b,&c,str),add(a,b,c),add(b,a,c);
dfs(1,0),s[maxx]=0,dfs(maxx,0);
printf("%d",s[maxx]);
return 0;
}

【BZOJ3364】[Usaco2004 Feb]Distance Queries 距离咨询

Description

    奶牛们拒绝跑马拉松,因为她们悠闲的生活无法承受约翰选择的如此长的赛道.因此约翰决心找一条更合理的赛道,他打算咨询你.此题的地图形式与前两题相同.但读入地图之后,会有K个问题.每个问题包括2个整数,就是约翰感兴趣的2个农场的编号,请尽快算出这2个农场间的距离.

Input

    第1到I+M行:与前两题相同;
    第2+M行:一个整数K(1≤K≤10000).
    第3+M到2+M+K行:每行输入2个整数,代表两个农场.

Output

    对每个问题,输出单独的一个整数,给出正确的距离.

Sample Input

7 6
1 6 13 E
6 3 9 E
3 5 7 S
4 1 3 N
2 4 20 W
4 7 2 S
3
1 6
1 4
2 6

Sample Output

13
3
36
农场2到农场6有20+3+13=36的距离

题解:倍增LCA

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn=40010;
int n,m,cnt,ans;
int to[maxn<<1],next[maxn<<1],head[maxn],val[maxn<<1],f[maxn][25],s[maxn],dep[maxn];
char str[5];
void add(int a,int b,int c)
{
to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
}
void dfs(int x)
{
for(int i=head[x];i!=-1;i=next[i]) if(to[i]!=f[x][0]) f[to[i]][0]=x,dep[to[i]]=dep[x]+1,s[to[i]]=s[x]+val[i],dfs(to[i]);
}
int main()
{
scanf("%d%d",&n,&m);
int i,j,a,b,c;
memset(head,-1,sizeof(head));
for(i=1;i<=m;i++) scanf("%d%d%d%s",&a,&b,&c,str),add(a,b,c),add(b,a,c);
dfs(1);
for(j=1;(1<<j)+1<=n;j++) for(i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1];
scanf("%d",&m);
for(i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
ans=s[a]+s[b];
if(dep[a]<dep[b]) swap(a,b);
for(j=20;j>=0;j--) if(dep[a]-(1<<j)>=dep[b]) a=f[a][j];
if(a==b)
{
printf("%d\n",ans-2*s[a]);
continue;
}
for(j=20;j>=0;j--) if(f[a][j]!=f[b][j]) a=f[a][j],b=f[b][j];
ans-=2*s[f[a][0]];
printf("%d\n",ans);
}
return 0;
}

【BZOJ3365】[Usaco2004 Feb]Distance Statistics 路程统计

Description

    在得知了自己农场的完整地图后(地图形式如前三题所述),约翰又有了新的问题.他提供
一个整数K(1≤K≤109),希望你输出有多少对农场之间的距离是不超过K的.

Input

    第1到I+M行:与前三题相同;
    第M+2行:一个整数K.

Output

    农场之间的距离不超过K的对数.

Sample Input

7 6
1 6 13 E
6 3 9 E
3 5 7 S
4 1 3 N
2 4 20 W
4 7 2 S
10

Sample Output

5
有五对道路之间的距离小于10
1-4,距离为3
4-7,距离为2
1-7,距离为5
3-5,距离为7
3-6,距离为9

题意:同POJ1741,同BZ1468

题解:点分治,第一次写感觉自己代码常数∞∞∞

谈谈点分治吧~

我们对以x节点为根的子树进行分治,只考虑经过x的路径,然后递归计算不经过x的路径,所以现在问题是怎么求x的子树中有多少条长度≤K的路径

我们先求出x子树中所有点到x的深度dep[i],那么我们要的就是dep[i]+dep[j]≤K的(i,j)对数,然后呢?

我们采用双指针法来实现这个过程。我们先将dep排序,用两个指针l,r从区间两边向中间平移,始终保证dep[l]+dep[r]≤K,那么(l,r]中的点到l的路径长度就都≤K,直接更新答案,单次计算时间复杂度O(nlogn)

但问题又出现了,这样计算可能导致(i,j)的路径不经过x也可能被算进去,于是我们依次算出x的儿子的子树中(i,j)的对数(此时dep[i]还是i到x的深度),然后用ans减去这些重复的对数就好了

这样,我们层层递归下去,如果给你的树比较平滑,那么总的时间复杂度应该不会太高;但假如给你的树是一条链,那么是时间复杂度直接O(n*nlogn),连暴力都不如

于是我们不能以1为根来搞,而是要以树的重心为根(树的重心指:删去这个点后,使所有连通块的点个数的最大值最小),并且每次递归都要重新找出子树中的重心向下搜(我原来只找了整棵树的重心。。。),这样每个点至多出现在log个点的子树中,才能保证时间复杂度为O(nlogn*logn)

为什么改了那么多遍感觉常数还是std的214748647倍~~~

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
const int maxn=40010;
char str[5];
int n,k,cnt,root,maxx,ans,tot;
int to[maxn<<1],next[maxn<<1],head[maxn],val[maxn<<1],dep[maxn<<1],p[maxn<<1],siz[maxn],vis[maxn];
void getroot(int x,int fa)
{
int i,tmp=0;
siz[x]=1;
for(i=head[x];i!=-1;i=next[i])
{
if(to[i]==fa||vis[to[i]]) continue;
getroot(to[i],x);
siz[x]+=siz[to[i]];
tmp=max(tmp,siz[to[i]]);
}
if(max(tot-siz[x],tmp)<maxx) maxx=max(tot-siz[x],tmp),root=x;
}
void getdep(int x,int fa)
{
p[++p[0]]=dep[x];
for(int i=head[x];i!=-1;i=next[i])
{
if(to[i]==fa||vis[to[i]]) continue;
dep[to[i]]=dep[x]+val[i],getdep(to[i],x);
}
}
int solve(int x)
{
p[0]=0,getdep(x,0);
int ret=0,l=1,r=p[0];
sort(p+1,p+p[0]+1);
while(l<r)
{
while(l<r&&p[l]+p[r]>k) r--;
ret+=r-l,l++;
}
return ret;
}
void dfs(int x)
{
int i;
vis[x]=1,dep[x]=0,ans+=solve(x);
for(i=head[x];i!=-1;i=next[i])
{
if(vis[to[i]]) continue;
dep[to[i]]=val[i],ans-=solve(to[i]);
maxx=1<<30,tot=siz[to[i]],getroot(to[i],x);
dfs(root);
}
}
void add(int a,int b,int c)
{
to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
}
int main()
{
int i,a,b,c;
scanf("%d%d",&n,&a);
memset(head,-1,sizeof(head));
tot=n,root=1,maxx=1<<30;
for(i=1;i<n;i++)
{
scanf("%d%d%d%s",&a,&b,&c,str);
add(a,b,c),add(b,a,c);
}
scanf("%d",&k);
getroot(root,0);
dfs(root);
printf("%d\n",ans);
return 0;
}

【BZOJ3362-3365】USACO水题四连A的更多相关文章

  1. 搜索水题四连发_C++

    特别声明:以下题目有部分为原创题,涉及版权问题,不得转载,违者追究 法律责任! 话说这是一套神题,只有你想不到,没有你做不到 题目更正后比 Pascal 跑得还快哈~ 一道特别裸,但是特别坑的搜索题 ...

  2. USACO CHAPTER 1 1.1 Ride 水题

    水题,主要是学习文件输入输出. /* ID: ijustwa1 LANG: C++ TASK: ride */ #include<cstdio> #include<cstring&g ...

  3. BZOJ USACO 银组 水题集锦

    最近刷银组刷得好欢快,好像都是水题,在这里吧他们都记录一下吧(都是水题大家一定是道道都虐的把= =)几道比较神奇的题到时再列出来单独讲一下吧= =(其实我会说是BZOJ蹦了无聊再来写的么 = =) [ ...

  4. CF451C Predict Outcome of the Game 水题

    Codeforces Round #258 (Div. 2) Predict Outcome of the Game C. Predict Outcome of the Game time limit ...

  5. CCF 201612-1 最大波动 (水题)

    问题描述 小明正在利用股票的波动程度来研究股票.小明拿到了一只股票每天收盘时的价格,他想知道,这只股票连续几天的最大波动值是多少,即在这几天中某天收盘价格与前一天收盘价格之差的绝对值最大是多少. 输入 ...

  6. Codeforces Gym 100531G Grave 水题

    Problem G. Grave 题目连接: http://codeforces.com/gym/100531/attachments Description Gerard develops a Ha ...

  7. HDU 5832 A water problem (带坑水题)

    A water problem 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5832 Description Two planets named H ...

  8. 没讲明白的水题orz

    有一道解释程序的水题没给非计算机专业的同学讲明白orz,在这里再练一下.. 源代码完全没有缩进真是难以忍受.. p.s.懂递归就不用看了#include <stdio.h> int n = ...

  9. POJ 水题(刷题)进阶

    转载请注明出处:優YoU http://blog.csdn.net/lyy289065406/article/details/6642573 部分解题报告添加新内容,除了原有的"大致题意&q ...

随机推荐

  1. WCF客户端获取服务器返回数据报错

    错误信息:An error occurred while receiving the HTTP response to http://127.0.0.1/SIHIS/Infection/PubExec ...

  2. tomcat安装不成功.提示:failed to install tomcat6 service ,check your setting and permissions

    这个问题主要是因为旧版本卸载不完全导致的,可通过彻底删除旧版本解决,方案如下: 以管理员身份运行 命令提示符,弹出窗口 ,选择“是”,输入 sc delete tomcat5 ,或者 sc delet ...

  3. Android ListView 笔记

    ListView以列表的形式展示数据内容. 布局文件如下所示,添加一个ListView. activity_main.xml <?xml version="1.0" enco ...

  4. try except 异常处理

    1.捕获指定异常 2.捕获所有异常

  5. 有一个TIME的类要求输出分和秒的值

    #include <iostream> /* run this program using the console pauser or add your own getch, system ...

  6. webBrowser1.Document.Cookie取不到HttpOnly的Cookie,取Cookie不完整【转】

    在做数据采集时,有些网站需要输入验证码,但各网站验证码都不同,不可能有完美的识别验证码的代码,所以我也没去研究,我所采取的方案是:在winform里通过WebBrowser调用网页先手动登录系统,然后 ...

  7. R语言boxplot绘图函数

    boxplot 用于绘制箱线图,我们都知道boxplot 用于展示一组数据的总体分布,在R语言中,支持两种输入数据的方式 第一种:x , 这个参数指定用于绘制箱线图所用的数据,是一个向量 代码示例: ...

  8. git call failed: [git clone Could not resolve host: git.openstack.org

    git config --global http.proxy $http_proxy git config --global https.proxy $https_proxy ref: http:// ...

  9. 一些 Linux 常用命令说明

    目前由于自己接触到的是 Windows 的操作系统,所以会经常使用 git bash 来提交代码到 github上. git bash 是 Windows 下模拟 Linux 的命令行工具. 在此总结 ...

  10. 一个窗口里包含一个iframe,点击iframe内的submit按钮,返回的视图总是显示在iframe中,我想要的效果是点击按钮后返回的视图是在浏览器窗口中...?asp.net mvc 的action中,不用js怎么实现??????????

    Content("<script type='text/javascript'>parent.location.href = '" + url + "';&l ...