codevs 4633 [Mz]树链剖分练习

线段树的pushdown千万不能写错。要不然会WA整整6天。。。。。lol

裸树剖。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define maxn 1000050
#define maxe 200500
#define maxv 100500
using namespace std;
struct edge
{
long long v,nxt;
}e[maxe];
long long n,q,type,a,b;
long long ls[maxn],rs[maxn],value[maxn],lazy[maxn],nume=0,tot=0,root,cnt=0;
long long w[maxv],top[maxv],son[maxv],fath[maxv],dis[maxv],size[maxv],g[maxv];
void addedge(long long u,long long v)
{
e[++nume].v=v;
e[nume].nxt=g[u];
g[u]=nume;
e[++nume].v=u;
e[nume].nxt=g[v];
g[v]=nume;
}
long long build(long long left,long long right)
{
long long mid=(left+right)>>1;
long long now=++tot;
if (left==right) return now;
ls[now]=build(left,mid);
rs[now]=build(mid+1,right);
value[now]=0;lazy[now]=0;
return now;
}
void dfs1(long long x)
{
size[x]=1;son[x]=0;
for (long long i=g[x];i;i=e[i].nxt)
{
long long v=e[i].v;
if (v!=fath[x])
{
dis[v]=dis[x]+1;
fath[v]=x;
dfs1(v);
if (size[v]>size[son[x]])
son[x]=v;
size[x]=size[x]+size[v];
}
}
}
void dfs2(long long x,long long father)
{
top[x]=father;w[x]=++cnt;
if (son[x]!=0) dfs2(son[x],father);
for (long long i=g[x];i;i=e[i].nxt)
{
long long v=e[i].v;
if ((v!=fath[x]) && (v!=son[x]))
dfs2(v,v);
}
}
void pushdown(long long x,long long left,long long right)
{
if (lazy[x]!=0)
{
long long lson=ls[x],rson=rs[x];
long long mid=(left+right)>>1;
lazy[lson]+=lazy[x];
lazy[rson]+=lazy[x];
value[lson]+=lazy[x]*(mid-left+1);
value[rson]+=lazy[x]*(right-mid);
lazy[x]=0;
}
}
void modify(long long now,long long left,long long right,long long l,long long r)
{
if ((l==left) && (r==right))
{
lazy[now]+=1;
value[now]=value[now]+(right-left+1);
return;
}
pushdown(now,left,right);
long long mid=(left+right)>>1;
if (r<=mid) modify(ls[now],left,mid,l,r);
else if (l>=mid+1) modify(rs[now],mid+1,right,l,r);
else
{
modify(ls[now],left,mid,l,mid);
modify(rs[now],mid+1,right,mid+1,r);
}
value[now]=value[ls[now]]+value[rs[now]];
}
long long ask(long long now,long long left,long long right,long long l,long long r)
{
if ((l==left) && (r==right))
return value[now];
pushdown(now,left,right);
long long mid=(left+right)>>1;
if (r<=mid) return ask(ls[now],left,mid,l,r);
else if (l>=mid+1) return ask(rs[now],mid+1,right,l,r);
else return ask(ls[now],left,mid,l,mid)+ask(rs[now],mid+1,right,mid+1,r);
}
void work1(long long a,long long b)
{
long long f1=top[a],f2=top[b];
while (f1!=f2)
{
if (dis[f1]<dis[f2])
{
swap(f1,f2);
swap(a,b);
}
modify(1,1,cnt,w[f1],w[a]);
a=fath[f1];f1=top[a];
}
if (dis[a]>dis[b])
swap(a,b);
modify(1,1,cnt,w[a],w[b]);
}
void work2(long long a,long long b)
{
long long ans=0;
long long f1=top[a],f2=top[b];
while (f1!=f2)
{
if (dis[f1]<dis[f2])
{
swap(f1,f2);
swap(a,b);
}
ans=ans+ask(1,1,cnt,w[f1],w[a]);
a=fath[f1];f1=top[a];
}
if (dis[a]>dis[b])
swap(a,b);
ans=ans+ask(1,1,cnt,w[a],w[b]);
printf("%lld\n",ans);
}
void work()
{
scanf("%lld%lld%lld",&type,&a,&b);
if (type==1) work1(a,b);
else work2(a,b);
}
int main()
{
memset(g,0,sizeof(g));
scanf("%lld",&n);
for (long long i=1;i<=n-1;i++)
{
scanf("%lld%lld",&a,&b);
addedge(a,b);
}
root=build(1,n);
dfs1(1);
dfs2(1,1);
scanf("%lld",&q);
for (long long k=1;k<=q;k++)
work();
return 0;
}

你可能感兴趣的:(codevs 4633 [Mz]树链剖分练习)