BZOJ3531: [Sdoi2014]旅行
题解: 走路的时候 YY的一种写法啊 直接对于每个信仰动态开点然后维护最大值和区间和即可
#include <bits/stdc++.h> #define ll long long #define link(x) for(edge *j=h[x];j;j=j->next) const int MAXN=1e5+10; using namespace std; int rt[MAXN],n,q; ll read(){ ll x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return f*x; } struct edge{int v;edge*next;}e[MAXN<<1],*h[MAXN<<1],*o=e; void add(int x,int y){o->v=y;o->next=h[x];h[x]=o++;} typedef struct node{ int l,r,sum,maxx; }node; int a[MAXN],b[MAXN]; node d[MAXN*21];int cnt; void up(int x){ d[x].sum=d[d[x].l].sum+d[d[x].r].sum; d[x].maxx=max(d[d[x].l].maxx,d[d[x].r].maxx); } void update(int &x,int l,int r,int t,int vul){ if(!x)x=++cnt; if(l==r){d[x].sum=d[x].maxx=vul;return ;} int mid=(l+r)>>1; if(t<=mid)update(d[x].l,l,mid,t,vul); else update(d[x].r,mid+1,r,t,vul); up(x); } pair<int,int>ans; void querty(int x,int l,int r,int ql,int qr){ if(!x)return ; if(ql<=l&&r<=qr){ans.first+=d[x].sum;ans.second=max(ans.second,d[x].maxx);return ;} int mid=(l+r)>>1; if(ql<=mid)querty(d[x].l,l,mid,ql,qr); if(qr>mid)querty(d[x].r,mid+1,r,ql,qr); } int num[MAXN],son[MAXN],dep[MAXN],fa[MAXN]; void dfs(int v,int pre,int deep){ num[v]=1;dep[v]=deep+1;fa[v]=pre; link(v){ if(j->v!=pre){ dfs(j->v,v,deep+1); num[v]+=num[j->v]; if(son[v]==-1||num[son[v]]<num[j->v])son[v]=j->v; } } } int p[MAXN],fp[MAXN],cnt1,tp[MAXN]; void dfs1(int v,int td){ p[v]=++cnt1;fp[p[v]]=v;tp[v]=td; if(son[v]!=-1)dfs1(son[v],td); link(v)if(j->v!=son[v]&&j->v!=fa[v])dfs1(j->v,j->v); } int slove(int u,int v,int op,int c){ int uu=tp[u];int vv=tp[v]; ans.first=ans.second=0; while(uu!=vv){ if(dep[uu]<dep[vv])swap(uu,vv),swap(u,v); querty(rt[c],1,n,p[uu],p[u]); u=fa[uu];uu=tp[u]; } if(dep[u]>dep[v])swap(u,v); querty(rt[c],1,n,p[u],p[v]); if(op==1)return ans.first; return ans.second; } int main(){ int x,y;n=read();q=read(); char str[11]; for(int i=1;i<=n;i++)a[i]=read(),b[i]=read(),son[i]=-1; for(int i=1;i<n;i++)x=read(),y=read(),add(x,y),add(y,x); dfs(1,0,0); dfs1(1,1); for(int i=1;i<=n;i++)update(rt[b[i]],1,n,p[i],a[i]); for(int i=1;i<=q;i++){ scanf("%s",str);x=read();y=read(); if(str[1]=='C'){update(rt[b[x]],1,n,p[x],0);update(rt[y],1,n,p[x],a[x]);b[x]=y;} else if(str[1]=='W'){update(rt[b[x]],1,n,p[x],0);update(rt[b[x]],1,n,p[x],y);a[x]=y;} else if(str[1]=='S')printf("%d\n",slove(x,y,1,b[x])); else printf("%d\n",slove(x,y,2,b[x])); } return 0; }
3531: [Sdoi2014]旅行
Time Limit: 40 Sec Memory Limit: 512 MBSubmit: 3105 Solved: 1385
[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”:一位旅行者从城市x出发,到城市y,并记下了途中留宿过的城市的评级总和;
”QM x y”:一位旅行者从城市x出发,到城市y,并记下了途中留宿过
的城市的评级最大值。
由于年代久远,旅行者记下的数字已经遗失了,但记录开始之前每座城市的信仰与评级,还有事件记录本身是完好的。请根据这些信息,还原旅行者记下的数字。 为了方便,我们认为事件之间的间隔足够长,以致在任意一次旅行中,所有城市的评级和信仰保持不变。
Input
输入的第一行包含整数N,Q依次表示城市数和事件数。
接下来N行,第i+l行两个整数Wi,Ci依次表示记录开始之前,城市i的
评级和信仰。
接下来N-1行每行两个整数x,y表示一条双向道路。
接下来Q行,每行一个操作,格式如上所述。
Output
对每个QS和QM事件,输出一行,表示旅行者记下的数字。
Sample Input
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
9
11
3
HINT
N,Q < =10^5 , C < =10^5
数据保证对所有QS和QM事件,起点和终点城市的信仰相同;在任意时
刻,城市的评级总是不大于10^4的正整数,且宗教值不大于C。