3531: [Sdoi2014]旅行

来源:互联网 发布:海关数据怎么贩卖 编辑:程序博客网 时间:2024/05/23 02:02

3531: [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,并记下了途中留宿过
的城市的评级最大值。
由于年代久远,旅行者记下的数字已经遗失了,但记录开始之前每座城市的信仰与评级,还有事件记录本身是完好的。请根据这些信息,还原旅行者记下的数字。 为了方便,我们认为事件之间的间隔足够长,以致在任意一次旅行中,所有城市的评级和信仰保持不变。

Input

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

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

Output

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

Sample Input

5 63 12 31 23 35 11 21 33 43 5QS 1 5CC 3 1QS 1 5CW 3 3QS 1 5QM 2 4

Sample Output

89113

HINT

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

这么水的一个题一开始还想挫了。。
觉得要是跑树链剖分的话,每个点开10^5空间会出事。。、
于是考虑树上待修改莫队,10^5的5/3次方,2S肯定也过不了。。
一开始还想试一下来着。。
然后发现,其实不用每个节点开啊,我们就动态开点就好了。。
实际有用的节点很少。。
QAQ,这种水题还弄了这么就,看来我还是太菜了

#include<cstdio>#include<iostream>#include<cstring>using namespace std;const int N=100005;int W[N],C[N];int n,q;struct qq{int x,y,last;}e[N*2];int num,last[N];void init (int x,int y){    num++;    e[num].x=x; e[num].y=y;    e[num].last=last[x];    last[x]=num;}int dep[N],tot[N],top[N],son[N],ys[N],f[N];void dfs (int x,int fa){    f[x]=fa;tot[x]=1;dep[x]=dep[fa]+1;    for (int u=last[x];u!=-1;u=e[u].last)    {        int y=e[u].y;        if (y==fa) continue;        dfs(y,x);        tot[x]+=tot[y];        if (tot[y]>tot[son[x]]) son[x]=y;    }}int ooo=0;void dfs2 (int x,int tp){    ys[x]=++ooo;top[x]=tp;    if (son[x]!=0) dfs2(son[x],tp);    for (int u=last[x];u!=-1;u=e[u].last)    {        int y=e[u].y;        if (y==f[x]||y==son[x]) continue;        dfs2(y,y);    }}const int NN=N*100*2;int s1[NN],s2[NN],c[NN],c1[NN];int lalal=0;int root[N];void update (int now){    c[now]=max(c[s1[now]],c[s2[now]]);    c1[now]=c1[s1[now]]+c1[s2[now]];}void change (int &now,int l,int r,int x,int y)//要把这个节点改为这个 {    if (now==0) now=++lalal;    if (l==r){c[now]=y;c1[now]=y;return ;}    int mid=(l+r)>>1;    if (x<=mid) change(s1[now],l,mid,x,y);    else change(s2[now],mid+1,r,x,y);    update(now);}void give (int &rt1,int &rt2,int l,int r,int x){    if (l==r){rt2=rt1;rt1=0;return ;}    if (rt2==0) rt2=++lalal;    int mid=(l+r)>>1;    if (x<=mid) give(s1[rt1],s1[rt2],l,mid,x);    else give(s2[rt1],s2[rt2],mid+1,r,x);    update(rt1);update(rt2);}int find (int now,int l,int r,int L,int R){    if (now==0) return 0;    if (l==L&&r==R) return c1[now];    int mid=(l+r)>>1;    if (R<=mid) return find(s1[now],l,mid,L,R);    else if (L>mid) return find(s2[now],mid+1,r,L,R);    else return find(s1[now],l,mid,L,mid)+find(s2[now],mid+1,r,mid+1,R);}int ans;int solve (int x,int y,int a)//起点终点    用的线段树 //总和 {    ans=0;    int tx=top[x],ty=top[y];    if (dep[tx]>dep[ty]) {swap(x,y);swap(tx,ty);}//让y来跳    while (tx!=ty)    {        ans=ans+find(root[a],1,ooo,ys[ty],ys[y]);           y=f[ty];ty=top[y];        if (dep[tx]>dep[ty]) {swap(x,y);swap(tx,ty);}    }    if (dep[x]>dep[y]) swap(x,y);    ans=ans+find(root[a],1,ooo,ys[x],ys[y]);    return ans;}int find1 (int now,int l,int r,int L,int R){    if (now==0) return 0;    if (l==L&&r==R) return c[now];    int mid=(l+r)>>1;    if (R<=mid) return find1(s1[now],l,mid,L,R);    else if (L>mid) return find1(s2[now],mid+1,r,L,R);    else return max(find1(s1[now],l,mid,L,mid),find1(s2[now],mid+1,r,mid+1,R));}int solve1 (int x,int y,int a){    ans=0;    int tx=top[x],ty=top[y];    if (dep[tx]>dep[ty]) {swap(x,y);swap(tx,ty);}//让y来跳    while (tx!=ty)    {        //printf("%d %d %d %d\n",x,y,tx,ty);        ans=max(ans,find1(root[a],1,ooo,ys[ty],ys[y]));         y=f[ty];ty=top[y];        if (dep[tx]>dep[ty]) {swap(x,y);swap(tx,ty);}    }    //printf("%d %d\n",x,y);    if (dep[x]>dep[y]) swap(x,y);    ans=max(ans,find1(root[a],1,ooo,ys[x],ys[y]));    return ans;}int main(){    num=0;memset(last,-1,sizeof(last));    scanf("%d%d",&n,&q);    for (int u=1;u<=n;u++)  scanf("%d%d",&W[u],&C[u]);    for (int u=1;u<n;u++)    {        int x,y;        scanf("%d%d",&x,&y);        init(x,y);init(y,x);    }    dfs(1,0);    dfs2(1,1);/*  for (int u=1;u<=n;u++)        printf("%d %d %d\n",dep[u],top[u],ys[u]);*/    for (int u=1;u<=n;u++)  change(root[C[u]],1,ooo,ys[u],W[u]);    while (q--)    {        char ss[5];        scanf("%s",ss);        if (ss[1]=='C')//改信        {            int x,c;            scanf("%d%d",&x,&c);            give(root[C[x]],root[c],1,ooo,ys[x]);            C[x]=c;        }        else if (ss[1]=='W')        {            int x,c;            scanf("%d%d",&x,&c);            change(root[C[x]],1,ooo,ys[x],c);        }        else if (ss[1]=='S')//评级总和         {            int x,y;            scanf("%d%d",&x,&y);            printf("%d\n",solve(x,y,C[x]));        }        else        {            int x,y;            scanf("%d%d",&x,&y);            printf("%d\n",solve1(x,y,C[x]));        }    }    return 0;}
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 玩游戏扣的话费怎么办 转笔实在是不会怎么办 滑板l轴承沾水了怎么办 暗影格斗3闪退怎么办 暗影格斗3文档被删怎么办 dnf手残党偷学技能学不了怎么办 打篮球没热身膝盖酸痛是怎么办 无线路由器lan口少怎么办? 电脑ip设置乱了怎么办 监控拍我我偷钱怎么办 网吧上网密码忘记了怎么办 比熊犬晚上叫怎么办 刚买的狗一直叫怎么办 酒驾罚款2年没交怎么办 法院判罚款没有钱怎么办 有人朝你吐口水怎么办 孕妇用了六神花露水怎么办 出车祸人不赔钱怎么办 交通事故对方保险不签字怎么办 肇事车主联系不上怎么办 商标被别人申请无效宣告怎么办 淘宝上传宝贝没有品牌怎么办 萌虎白卡借款2000逾期了怎么办 最里面的牙齿烂了怎么办 金龙沉底不游怎么办 龙鱼尾巴烂了怎么办 微博忘了登录名和密码怎么办 新浪微博密码忘了怎么办 vivo手机用户密码忘了怎么办 微博登录名忘记了怎么办 微信忘记密码钱怎么办 微信密码申诉失败怎么办 微博密码被盗了怎么办 对公密码器丢了怎么办 手机qq忘记旧密码怎么办 qq旧密码忘记了怎么办 微博账户密码忘记了怎么办 三星盖乐世s3忘记密码了怎么办 微博登录密码忘记了怎么办 助学贷款密码忘了怎么办 助学贷款的密码忘了怎么办