您的位置:首页 > 其它

ZOJ 3522 Hide and seek

2017-01-17 19:32 113 查看
题目大意:大小姐与二小姐玩捉迷藏。红魔馆里有N(1<=N<=50000)个可以

来躲的地方,N-1条双向边连接所有的地方(就是一棵树),芙兰有100000

组询问问如果X,Y之间添加一条长度为L的边,树上所有点到X最短距离变化值

与到Y变化值之和。

看到这题题面跟东方有关就做了……咱用LCT做的。维护一大堆迷之变量: 虚儿

子大小的总和num,所在子树大小siz,所在splay子树上边权和sum,以及

(难以描述)ran和lan。

对于求所有点到t点的距离,先把t点提到根,再把新加的边连到的s点access一

下,在原本的路径上找到一个点p,使得t从原路径到p的距离与t从新路径到p

距离基本相等。认为p点以下的点都受到了新加边的影响,所以每个点认为对

答案造成了(s到t原路径长度-新路径长度)的影响。由于每个点的影响由于位

置不同,会有一些差值。lan和ran就是记录这个差值的。

在把t提到根节点的过程中,边权不太好维护。看到一种方法,就是把边视为

权值为L但不计入siz和num的点,而正常点的权值为0。感到学习到了非常棒

的姿势……

写这个玩意错了好多次,问题主要在找p点和long long……果然咱还是太弱

了。

细节还是有点多,得注意下。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn=100100;
int n;
int wea;
int stk[maxn],top;
int beg[maxn],w[maxn<<2][3],e;
void putin(int s,int t,int v)
{
w[++e][0]=t;
w[e][1]=beg[s];
beg[s]=e;
w[e][2]=v;
}
struct LCT{
long long l[maxn],r[maxn],f[maxn],rev[maxn],siz[maxn],sum[maxn],num[maxn],lan[maxn],ran[maxn],val[maxn];
void csh()
{
memset(l,0,sizeof(l));
memset(r,0,sizeof(r));
memset(f,0,sizeof(f));
memset(rev,0,sizeof(rev));
memset(lan,0,sizeof(lan));
memset(ran,0,sizeof(ran));
memset(siz,0,sizeof(siz));
memset(num,0,sizeof(num));
memset(beg,0,sizeof(beg));
memset(val,0,sizeof(val));
e=0;
}
bool isroot(int h)
{
if(!f[h])
return 1;
if(l[f[h]]==h||r[f[h]]==h)
return 0;
return 1;
}
void push_down(int h)
{
if(!rev[h]) return;
long long tmp;
tmp=l[h];l[h]=r[h];r[h]=tmp;
rev[l[h]]^=1;rev[r[h]]^=1;
rev[h]=0;
swap(lan[h],ran[h]);   //开始tmp是int,害咱错了好⑨
}
void push_up(int h)
{
if(h==0) return;
push_down(h);
push_down(l[h]);
push_down(r[h]);//这里的push_down(似乎)很重要
siz[h]=siz[l[h]]+siz[r[h]]+num[h];
sum[h]=sum[l[h]]+sum[r[h]]+val[h];
lan[h]=lan[r[h]] + (sum[l[h]]+val[h])*siz[r[h]] + sum[l[h]]*num[h] + lan[l[h]];
ran[h]=ran[l[h]] + (sum[r[h]]+val[h])*siz[l[h]] + sum[r[h]]*num[h] + ran[r[h]];
}//看push_up基本就可以理解lan和ran的含义了
void rotate(int h)
{
int fa=f[h],gfa=f[fa];
if(fa==l[gfa]) l[gfa]=h;
else if(fa==r[gfa]) r[gfa]=h;
f[h]=gfa;
if(h==l[fa])
{
l[fa]=r[h];f[r[h]]=fa;
r[h]=fa;f[fa]=h;
}
else
{
r[fa]=l[h];f[l[h]]=fa;
l[h]=fa;f[fa]=h;
}
push_up(fa);push_up(h);push_up(gfa);
}
void splay(int h)
{
int fa,gfa;
top=1;
stk[top]=h;
for(int pos=h;!isroot(pos);pos=f[pos])
stk[++top]=f[pos];
while(top)
{
push_down(stk[top]);
top--;
}//printf("%d %d\n",sum[h],f[h]);

while(!isroot(h))
{
fa=f[h];//if(wea==2){printf("?\n");system("pause");}
if(isroot(fa))
{
rotate(h);
return;
}
gfa=f[fa];
if((h==l[fa])^(fa==l[gfa]))
{
rotate(h);
rotate(h);
}
else
{
rotate(fa);
rotate(h);
}
}
}
void access(int x)
{
int s=0;

while(x)
{
splay(x);
num[x]+=siz[r[x]];
r[x]=s;
num[x]-=siz[r[x]];
push_up(x);
s=x;x=f[x];
}
}
void makeroot(int x)
{
access(x);
splay(x);
rev[x]^=1;
}
int findv(int u,long long v)
{
int st=0;
while(u)
{
push_down(u);
if((val[u]+sum[l[u]])*2<=v)
{
st=u;
v-=(val[u]+sum[l[u]])*2;
u=r[u];
}
else
u=l[u];
}
return st;
}//这个写法的find好像快一些
void dfs_bt(int u)
{
int v;
if(u<=n) siz[u]=1;
else siz[u]=0;
for(int i=beg[u];i;i=w[i][1])
{
v=w[i][0];
if(v==f[u])
continue;
f[v]=u;
dfs_bt(v);
siz[u]+=siz[v];
}
num[u]=siz[u];
}
void printh(int h)
{
push_down(h);
if(l[h]) printh(l[h]);
cerr<<h<<" ";
if(r[h]) printh(r[h]);
}
void printd(int h)
{
push_down(h);
if(l[h]) printd(l[h]);
if(r[h]) printd(r[h]);
}//调试用
}lct;
long long work(int s,int t,long long v)
{
if(s==t) return 0;
lct.makeroot(t);
lct.access(s);
lct.splay(s);
long long tt=lct.sum[s];
if(v>=tt) return 0;
int p=lct.findv(s,tt+v);
if(!p) return 0;
lct.splay(p);
lct.push_down(p);
lct.push_down(lct.r[p]);
long long cnt=lct.siz[lct.r[p]];
return cnt*(tt-v)-lct.ran[lct.r[p]]*2;
}
int main(){
//  freopen("in.txt","r",stdin);
//  freopen("out.txt","w",stdout);
int Q;
int s,t;
long long v;
long long ans1,ans2;
while(scanf("%d",&n)!=EOF)
{
lct.csh();
for(int i=1;i<=n-1;i++)
{
scanf("%d%d%lld",&s,&t,&v);
lct.val[n+i]=lct.sum[n+i]=v;
putin(s,n+i,v);
putin(n+i,s,v);
putin(t,n+i,v);
putin(n+i,t,v);//把边当做点
}
lct.dfs_bt(1);
scanf("%d",&Q);
while(Q--)
{
scanf("%d%d%lld",&s,&t,&v);
ans2=work(t,s,v);
ans1=work(s,t,v);
printf("%lld\n",ans1+ans2);

}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  zoj