Sunshine’s city(lct+线段树)

来源:互联网 发布:中金公司 知乎 编辑:程序博客网 时间:2024/06/08 13:31

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 longusing 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; }}


0 0
原创粉丝点击