程序员人生 网站导航

【BZOJ 3531】 [Sdoi2014]旅行

栏目:php教程时间:2015-04-14 08:06:40

3531: [Sdoi2014]旅行

Time Limit: 20 Sec Memory Limit: 512 MB
Submit: 575 Solved: 303
[Submit][Status][Discuss]
Description

S国有N个城市,编号从1到N。城市间用N⑴条双向道路连接,满足
从1个城市动身可以到达其它所有城市。每一个城市信仰不同的宗教,如飞天面条神教、隐形独角兽教、绝地教都是常见的信仰。为了方便,我们用不同的正整数代表各种宗教, S国的居民常常旅行。旅行时他们总会走最短路,并且为了不麻烦,只在信仰和他们相同的城市留宿。固然旅程的终点也是信仰与他相同的城市。S国政府为每一个城市标定了不同的旅行评级,旅行者们常会记下途中(包括出发点和终点)留宿过的城市的评级总和或最大值。
在S国的历史上常会产生以下几种事件:
”CC x c”:城市x的居民全部改信了c教;
”CW x w”:城市x的评级调剂为w;
”QS x y”:1位旅行者从城市x动身,到城市y,并记下了途中留宿过的城市的评级总和;
”QM x y”:1位旅行者从城市x动身,到城市y,并记下了途中留宿过
的城市的评级最大值。
由于年代久远,旅行者记下的数字已遗失了,但记录开始之前每座城市的信仰与评级,还有事件记录本身是完好的。请根据这些信息,还原旅行者记下的数字。 为了方便,我们认为事件之间的间隔足够长,以致在任意1次旅行中,所有城市的评级和信仰保持不变。

Input

输入的第1行包括整数N,Q顺次表示城市数和事件数。
接下来N行,第i+l行两个整数Wi,Ci顺次表示记录开始之前,城市i的

评级和信仰。
接下来N⑴行每行两个整数x,y表示1条双向道路。
接下来Q行,每行1个操作,格式如上所述。

Output

对每一个QS和QM事件,输出1行,表示旅行者记下的数字。

Sample Input

5 6

3 1

2 3

1 2

3 3

5 1

1 2

1 3

3 4

3 5

QS 1 5

CC 3 1

QS 1 5

CW 3 3

QS 1 5

QM 2 4

Sample Output

8

9

11

3

HINT

N,Q < =10^5 , C < =10^5

数据保证对所有QS和QM事件,出发点和终点城市的信仰相同;在任意时

刻,城市的评级总是不大于10^4的正整数,且宗教值不大于C。

Source

Round 1 Day 1

树链剖分+动态开结点。

如果没有同1个信仰的限制就是裸的树链剖分了。

我们可以对每个信仰都建1棵线段树,但是普通方法建线段树就会MLE。

因此我们采取动态开结点的办法:
假定n=5,我们要在线段树中加入1个id=4的人,那末我们只需要开”4⑸”这个结点,而不用开”1⑶”的结点,由于开了也没用。

在最坏情况下,每一个人都属于不同的信仰,我们对每一个信仰开1棵线段树,也只需要nlogn个节点了~

然后就是裸的树链剖分了。

#include <iostream> #include <algorithm> #include <cmath> #include <cstring> #include <cstdio> #include <cstdlib> #define M 100005 using namespace std; int id[M],n,now,q,h[M],tote=0,tot=0,fa[M],size[M],son[M],dep[M],top[M]; int root[M]; struct data { int c,w; }a[M]; struct Segtree { int l,r,ma,sum; }t[8000005]; struct edge { int y,ne; }e[M*2]; void Addedge(int x,int y) { e[++tote].y=y; e[tote].ne=h[x]; h[x]=tote; } void dfs1(int x,int f,int de) { dep[x]=de; size[x]=1; son[x]=0; fa[x]=f; for (int i=h[x];i;i=e[i].ne) { int y=e[i].y; if (y==f) continue; dfs1(y,x,de+1); size[x]+=size[y]; if (size[son[x]]<size[y]) son[x]=y; } } void dfs2(int x,int tp) { top[x]=tp; id[x]=++now; if (son[x]) dfs2(son[x],tp); for (int i=h[x];i;i=e[i].ne) { int y=e[i].y; if (y==son[x]||y==fa[x]) continue; dfs2(y,y); } } void Push_up(int x) { t[x].ma=max(t[t[x].l].ma,t[t[x].r].ma); t[x].sum=t[t[x].l].sum+t[t[x].r].sum; } void Build(int &x,int l,int r,int p,int v) { if (!x) x=++tot; if (l==r) { t[x].sum=t[x].ma=v; return; } int m=(l+r)>>1; if (p<=m) Build(t[x].l,l,m,p,v); else Build(t[x].r,m+1,r,p,v); Push_up(x); } int Getsum(int x,int lt,int rt,int l,int r) { if (!x) return 0; if (l<=lt&&rt<=r) return t[x].sum; int m=(lt+rt)>>1; int ans=0; if (l<=m) ans+=Getsum(t[x].l,lt,m,l,r); if (r>m) ans+=Getsum(t[x].r,m+1,rt,l,r); return ans; } int Qsum(int x,int y) { int C=a[x].c; int tp1=top[x],tp2=top[y]; int ans=0; while (tp1!=tp2) { if (dep[tp1]<dep[tp2]) swap(tp1,tp2),swap(x,y); ans+=Getsum(root[C],1,n,id[tp1],id[x]); x=fa[tp1]; tp1=top[x]; } if (x==y) return ans+(a[x].c==C)*a[x].w; if (dep[x]>dep[y]) swap(x,y); ans+=Getsum(root[C],1,n,id[x],id[y]); return ans; } int Getmax(int x,int lt,int rt,int l,int r) { if (!x) return 0; if (l<=lt&&rt<=r) return t[x].ma; int m=(lt+rt)>>1; int ans=0; if (l<=m) ans=Getmax(t[x].l,lt,m,l,r); if (r>m) ans=max(ans,Getmax(t[x].r,m+1,rt,l,r)); return ans; } int Qmax(int x,int y) { int C=a[x].c; int tp1=top[x],tp2=top[y]; int ans=0; while (tp1!=tp2) { if (dep[tp1]<dep[tp2]) swap(tp1,tp2),swap(x,y); ans=max(ans,Getmax(root[C],1,n,id[tp1],id[x])); x=fa[tp1]; tp1=top[x]; } if (x==y) return max(ans,(a[x].c==C)*a[x].w); if (dep[x]>dep[y]) swap(x,y); ans=max(ans,Getmax(root[C],1,n,id[x],id[y])); return ans; } int main() { now=0; scanf("%d%d",&n,&q); for (int i=1;i<=n;i++) scanf("%d%d",&a[i].w,&a[i].c); for (int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); Addedge(x,y); Addedge(y,x); } dfs1(1,0,1); dfs2(1,0); for (int i=1;i<=n;i++) Build(root[a[i].c],1,n,id[i],a[i].w); while (q--) { char s[5]; int x,y; scanf("%s",s); scanf("%d%d",&x,&y); if (s[0]=='C') { if (s[1]=='C') { Build(root[a[x].c],1,n,id[x],0); a[x].c=y; Build(root[a[x].c],1,n,id[x],a[x].w); } else { a[x].w=y; Build(root[a[x].c],1,n,id[x],a[x].w); } } else { if (s[1]=='S') printf("%d ",Qsum(x,y)); else printf("%d ",Qmax(x,y)); } } return 0; }

这里写图片描述
感悟:
这道题调了好久,由于树链剖分返回的时候没有判断最后1个点是不是是与出发点属于同1个信仰的。。

------分隔线----------------------------
------分隔线----------------------------

最新技术推荐