[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

 

posted @ 2017-03-30 07:27  F.W.Nietzsche  阅读(520)  评论(0编辑  收藏  举报