[SDOI2014]旅行解题报告
题目描述
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,并记下了途中留宿过的城市的评级最大值。
由于年代久远,旅行者记下的数字已经遗失了,但记录开始之前每座城市的信仰与评级,还有事件记录本身是完好的。请根据这些信息,还原旅行者记下的数字。 为了方便,我们认为事件之间的间隔足够长,以致在任意一次旅行中,所有城市的评级和信仰保持不变。
--by luogu
http://daniu.luogu.org/problem/show?pid=3313
得到模型——询问树上两点间路径中符合条件的点的加和与最值,支持单点修改权值和条件;
考虑建立C(宗教数)棵线段树——然后内存显然不够,
但可以不把她们开满:
如对于宗教i所属的线段树,只有属于宗教i的叶节点以及其祖先结构被建立;
相当于每个叶节点连一条向相应根的树链;
于是c棵线段树等价于n-条树链;
nlogn级内存;
对于每次宗教修改:
把原树上该点的权值清零,在该点的新宗教的树中建一条通向她的树链,为了方便下次修改,记得把原数组中的宗教值修改;
对于每次权值修改:
直接修改即可;
一个优化:
每次修改时动态的把已经为零的树链断开;
这样貌似可以减小查询的常数(因为当查询到不存在的树链时会直接返回)
然而实际评测时发现仿佛没什么用
代码如下:(精简而合适的代码)
1 #include<cstdio> 2 #include<cstring> 3 const int MAXN=100010; 4 int n,m,L,R; 5 int reli[MAXN],dis[MAXN],dep[MAXN],size[MAXN],fa[MAXN],hine[MAXN],rank[MAXN],top[MAXN],a[MAXN]; 6 struct pool{ 7 int sum,ls,rs,max; 8 }data[MAXN*30]; 9 int tot; 10 int root[MAXN]; 11 struct ss{ 12 int next,to; 13 }e[MAXN<<1]; 14 int first[MAXN],num; 15 void swap(int& a,int& b){int i=a;a=b;b=i;} 16 void Init(); 17 void build(int ,int ); 18 void dfs_1(int ); 19 void dfs_2(int ,int ); 20 void work(); 21 void chan_reli(int ,int ); 22 void chan_sum(int ,int ); 23 void get(int ,int ,int ); 24 void up(int ); 25 void builine(int ,int ,int&,int ,int ); 26 int g_sum(int ,int ,int ); 27 int g_max(int ,int ,int ); 28 int main() 29 { 30 Init(); 31 work(); 32 return 0; 33 } 34 void Init(){ 35 int i,j,k; 36 memset(dep,0,sizeof(dep)); 37 memset(size,0,sizeof(size)); 38 scanf("%d%d",&n,&m); 39 for(i=1;i<=n;i++) 40 scanf("%d%d",&dis[i],&reli[i]); 41 for(i=1;i<n;i++){ 42 hine[i]=i; 43 scanf("%d%d",&j,&k); 44 build(j,k);build(k,j); 45 } 46 hine[n]=n;dep[1]=1; 47 dfs_1(1);num=0; 48 dfs_2(1,1);num=0; 49 for(i=1;i<=n;i++) 50 builine(1,n,root[reli[a[i]]],i,dis[a[i]]); 51 } 52 void build(int f,int t){ 53 e[++num].next=first[f]; 54 e[num].to=t; 55 first[f]=num; 56 } 57 void dfs_1(int now){ 58 int i; 59 for(i=first[now];i;i=e[i].next) 60 if(!dep[e[i].to]){ 61 dep[e[i].to]=dep[now]+1; 62 fa[e[i].to]=now; 63 dfs_1(e[i].to); 64 size[now]+=size[e[i].to]; 65 if(hine[now]==now||size[e[i].to]>size[hine[now]]) 66 hine[now]=e[i].to; 67 } 68 size[now]++; 69 } 70 void dfs_2(int now,int now_top){ 71 int i; 72 top[now]=now_top; 73 rank[now]=++num; 74 a[num]=now; 75 if(hine[now]!=now) 76 dfs_2(hine[now],now_top); 77 for(i=first[now];i;i=e[i].next) 78 if(dep[e[i].to]==dep[now]+1&&e[i].to!=hine[now]) 79 dfs_2(e[i].to,e[i].to); 80 } 81 void work(){ 82 int i,j,k,u,v; 83 char s[3]; 84 for(i=1;i<=m;i++){ 85 scanf("%s%d%d",s,&u,&v); 86 switch(s[1]){ 87 case 'C':chan_reli(u,v);break; 88 case 'W':chan_sum(u,v);break; 89 case 'S':get(u,v,0);break; 90 case 'M':get(u,v,1);break; 91 } 92 } 93 } 94 void chan_reli(int u,int v){ 95 builine(1,n,root[v],rank[u],dis[u]); 96 builine(1,n,root[reli[u]],rank[u],0); 97 reli[u]=v; 98 } 99 void chan_sum(int u,int v){ 100 builine(1,n,root[reli[u]],rank[u],v); 101 dis[u]=v; 102 } 103 void get(int u,int v,int kind){ 104 int ans=0,ro=root[reli[u]],i,j,k; 105 while(top[u]!=top[v]){ 106 if(dep[top[u]]>dep[top[v]]){ 107 L=rank[top[u]];R=rank[u]; 108 u=fa[top[u]]; 109 } 110 else{ 111 L=rank[top[v]];R=rank[v]; 112 v=fa[top[v]]; 113 } 114 if(!kind) 115 ans+=g_sum(1,n,ro); 116 else{ 117 i=g_max(1,n,ro); 118 if(i>ans)ans=i; 119 } 120 } 121 if(dep[u]>dep[v]){ 122 swap(u,v); 123 } 124 L=rank[u];R=rank[v]; 125 if(!kind) 126 ans+=g_sum(1,n,ro); 127 else{ 128 i=g_max(1,n,ro); 129 if(i>ans)ans=i; 130 } 131 printf("%d\n",ans); 132 } 133 void up(int nu){ 134 data[nu].sum=data[data[nu].ls].sum+data[data[nu].rs].sum; 135 data[nu].max=data[data[nu].ls].max>data[data[nu].rs].max?data[data[nu].ls].max:data[data[nu].rs].max; 136 } 137 void builine(int l,int r,int&now,int x,int sum){ 138 if(!now){ 139 now=++tot; 140 } 141 if(l==r){ 142 data[now].sum=sum; 143 data[now].max=sum; 144 return ; 145 } 146 int mid=(l+r)>>1; 147 if(x<=mid) 148 builine(l,mid,data[now].ls,x,sum); 149 else 150 builine(mid+1,r,data[now].rs,x,sum); 151 up(now); 152 if(!data[now].sum)now=0; 153 } 154 int g_sum(int l,int r,int now){ 155 if(!now) 156 return 0; 157 if(L<=l&&r<=R) 158 return data[now].sum; 159 int mid=(l+r)>>1,ans=0; 160 if(L<=mid) 161 ans+=g_sum(l,mid,data[now].ls); 162 if(R>mid) 163 ans+=g_sum(mid+1,r,data[now].rs); 164 return ans; 165 } 166 int g_max(int l,int r,int now){ 167 if(!now) 168 return 0; 169 if(L<=l&&r<=R) 170 return data[now].max; 171 int mid=(l+r)>>1,lm=0,rm=0; 172 if(L<=mid) 173 lm=g_max(l,mid,data[now].ls); 174 if(R>mid) 175 rm=g_max(mid+1,r,data[now].rs); 176 if(lm>=rm) 177 return lm; 178 return rm; 179 }
祝AC