Sunshine’s city(city)
【问题描述】
在很久很久之前Sunshine建立了一个n个城市的王国 (城市从0开始编号) ,其中0 号城市是Sunshine 居住的地方,也就是首都。追求完美的 Sunshine国王把整个王国的道路设计成了一棵树的形状, 两个城市之间有且只有一条道路能到达。Sunshine 王国是一个文化多元的国家。初始时,每个城市都有一中单独的文化。当居民在相邻的城市间移动时,如果这两个城市不是同一种文化,那么需要付出一个单位的代价。体恤国民的 Sunshine 想要减少居民的支出。具体说来,他会每次将首都到一个城市u
路径上的所有城市都发展成一种新的文化。因为这个原因,来往于城市间的代价会经常改变, 于是Sunshine 找你来帮忙。 给定一个城市 u, 定义 f(u)为以u 为根的子树中所有节点到根节点的代价的和。【输入格式】
第一行有一个整数 n 表示城市的数目。 接下来 n-1 行每行两个整数Ai,Bi 表示一条连接这两点的道路。
接下来一行一个整数 m, 表示接下来有 m 组操作, 每组操作包含一个字符 t和一个整数 u。 如果 t='O',表示一个新的帮会占据了从首都到 u 路径上的城市。 如果 t='q',表示询问 f(u)。
【输出格式】
对于每组测试数据中的 t='q'类型的询问,输出一行一个整数表示 f(u)。
【样例输入】
13
0 1
0 2
1 11
1 10
1 9
9 12
2 5
5 8
2 4
2 3
4 6
4 7
7
q 0
O 4
q 6
q 2
O 9
q 9
q 2
【样例输出】
26
1
6
1
13
【数据规模及约定】
对于 30%的数据n,m<=1000
对于 60%的数据n,m<=50000
另外存在 20%的数据,树是一条链。
对于 100%的数据n,m<=200000
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 400003
#define LL long long
using namespace std;
int n,m;
int fa[N],ch[N][3],rev[N],st[N],col[N],pre[N];
int point[N],v[N],next[N],l[N],r[N],deep[N],tot,cur[N];
LL tr[N*4],delta[N*4];
int q[N],cnt;
void add(int x,int y)
{
tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y;
tot++; next[tot]=point[y]; point[y]=tot; v[tot]=x;
}
int isroot(int x)
{
return (ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x);
}
int get(int x)
{
return ch[fa[x]][1]==x;
}
void rotate(int x)
{
int y=fa[x]; int z=fa[y]; int which=get(x);
if (!isroot(y)) ch[z][ch[z][1]==y]=x;
ch[y][which]=ch[x][which^1]; fa[ch[x][which^1]]=y;
ch[x][which^1]=y; fa[y]=x; fa[x]=z;
}
/*void pushdown(int x)
{
if (rev[x])
{
swap(ch[x][1],ch[x][0]);
rev[ch[x][1]]^=1; rev[ch[x][0]]^=1;
rev[x]=0;
}
}*/
void splay(int x)
{
/*top=0; st[++top]=x;
for (int i=x;!isroot(i);i=fa[x])
st[++top]=fa[i];
for (int i=top;i>=1;i--)
pushdown(st[i]);*/
while(!isroot(x))
{
int y=fa[x];
if (!isroot(y))
rotate(get(x)==get(y)?y:x);
rotate(x);
}
}
void update(int x)
{
tr[x]=tr[x<<1]+tr[x<<1|1];
}
void pushdown(int l,int r,int now)
{
int mid=(l+r)/2;
if (delta[now]==0) return;
delta[now<<1]+=delta[now]; delta[now<<1|1]+=delta[now];
tr[now<<1]+=(LL)(mid-l+1)*delta[now]; tr[now<<1|1]+=(LL)(r-mid)*delta[now];
delta[now]=0;
}
void qjchange(int now,int l,int r,int ll,int rr,int v)
{
if (l>=ll&&r<=rr)
{
tr[now]+=(LL)(r-l+1)*(LL)v;
delta[now]+=(LL)v;
return;
}
pushdown(l,r,now);
int mid=(l+r)/2;
if (ll<=mid) qjchange(now<<1,l,mid,ll,rr,v);
if (rr>mid) qjchange(now<<1|1,mid+1,r,ll,rr,v);
update(now);
}
LL qjsum(int now,int l,int r,int ll,int rr)
{
if (l>=ll&&r<=rr) return tr[now];
pushdown(l,r,now);
int mid=(l+r)/2;
LL ans=0;
if (ll<=mid) ans+=qjsum(now<<1,l,mid,ll,rr);
if (rr>mid) ans+=qjsum(now<<1|1,mid+1,r,ll,rr);
return ans;
}
int find(int x)
{
while(ch[x][0]) x=ch[x][0];
return x;
}
void access(int x,int k)
{
int t=0;
while (x)
{
col[x]=k;
splay(x);
int t2=find(ch[x][1]);
if (t2)
qjchange(1,1,n,l[t2],r[t2],1);
ch[x][1]=t;
int t1=find(t);
if (t1) qjchange(1,1,n,l[t1],r[t1],-1);
t=x; x=fa[x];
}
}
void link(int x,int y)
{
fa[x]=y;
}
/*void dfs(int x,int f)
{
q[++cnt]=x;
l[x]=cnt;
for (int i=point[x];i;i=next[i])
if (v[i]!=f)
{
dfs(v[i],x);
}
r[x]=cnt;
}*/
void dfs1()
{
int top=0;
for (int i=1;i<=n;i++) cur[i]=point[i];
st[++top]=1; pre[1]=0;
while(top)
{
int x=st[top];
if (v[cur[x]]==pre[x]) cur[x]=next[cur[x]];
if (!cur[x])
{
--top;
r[x]=cnt;
continue;
}
int vt=v[cur[x]];
st[++top]=vt; pre[vt]=x; l[vt]=++cnt;
cur[x]=next[cur[x]];
}
}
int main()
{
freopen("city.in","r",stdin);
freopen("city.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<n;i++)
{
int x,y; scanf("%d%d",&x,&y);
x++; y++;
add(x,y); link(y,x);
}
//dfs(1,0);
dfs1();
//for (int i=1;i<=n;i++)
//cout<<l[i]<<" "<<r[i]<<endl;
for (int i=2;i<=n;i++)
qjchange(1,1,n,l[i],r[i],1);
//cout<<qjsum(1,1,n,1,n)<<endl;
scanf("%d",&m);
int size=n;
for (int i=1;i<=n;i++) col[i]=i;
for (int i=1;i<=m;i++)
{
char s[10]; int x;
scanf("%s%d",s+1,&x); x++;
if (s[1]=='q')
printf("%I64d\n",qjsum(1,1,n,l[x],r[x]));
else
access(x,++size);
//cout<<qjsum(1,1,n,1,n)<<endl;
}
}