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

n<=10^5

正确题解:对每种颜色都把关于这种颜色的操作全部存下来之后一起做,线段树上查,很简单很愉快

然后我讲讲我做这道题的艰难历程。

看到题目,yy了一会儿,树剖,然后每种颜色一棵平衡树,没毛病。

开始打代码,打什么平衡树呢?splay常数好像有点大,treap不熟练,算了就替罪羊吧。

轻松打完替罪羊,又看了看题目,哇居然要查最值!!!替罪羊怎么查啊?打了六七十行不想重打了,还好yy了一个类似线段树那样的查法,没毛病,但是效率就不太行了。

交一发,wa!然后开始对拍,改错。终于根本拍不出错了,交洛谷,a啦!然后交bzoj,心想终于a了,结果wa

 ???????我就懵逼,不知道怎么wa的只好找学长要数据,先放着呗。

然后第二天,感谢善良的学长拿到数据啦!测一发,woc只过了几个点,手测,fc一下,找不到差异.....赶紧找来ditoly看看看

然后发现一开O2就挂,不开就能a,心想玄学了。找了好久,最后发现,写函数 没  ! re !turn  ! 貌似不开o2自动返回最后一句话的值...加了一句话A了,感觉自己是个假人.....

不说了,代码8000B,SGT的操作都快要全了,都是泪。  

线段树做法大家自己yy吧,我对这题失去兴趣了

#include<iostream>
#include<cstdio>
#include<cstdlib>
#define getc() (*S++)
#define int long long
using namespace std;
char B[1<<25],*S=B;
inline int read()
{
    int x = 0 , f = 1; char ch = getc();
    while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getc();}
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getc();}
    return x * f;
}
 
namespace SGT
{
    #define MN 400000
    int fa[MN+5],cnt=0,c[MN+5][2],size[MN+5],nn[MN+5],rt[MN+5],mark=0,top=0,q[MN+5],s[MN+5],num[MN+5],mx[MN+5];
    bool b[MN+5];
    int tms=0;
    inline void update(int x)
    {
        int l=c[x][0],r=c[x][1];
        size[x]=size[l]+size[r]+b[x];
        s[x]=s[l]+s[r]+(b[x]?num[x]:0);
        mx[x]=max(mx[l],mx[r]);
        if(b[x]) mx[x]=max(mx[x],num[x]);
    }
    void ins(int&x,int rk,int n,int last)
    {
        if(!x){
            x=++cnt;fa[x]=last;num[x]=n;s[x]=n;mx[x]=n;
            size[x]=1;nn[x]=rk;b[x]=1;
            return;
        }
        if(nn[x]==rk)
        {
            b[x]=1;fa[x]=last;num[x]=n;s[x]=n;mx[x]=n;
            size[x]=1;nn[x]=rk;update(x);return;
        }
        ins(c[x][rk>nn[x]],rk,n,x);update(x);
        if(max(size[c[x][1]],size[c[x][0]])>0.7*size[x]) mark=x;
    }
    void del(int x,int k)
    {
        if(nn[x]==k&&b[x]) {b[x]=0;update(x);return;}
        del(c[x][nn[x]<k],k);update(x);
    }
    int query(int x,int rk)
    {
        if(!x) return 0;
        if(nn[x]>rk) return query(c[x][0],rk);   else
        return query(c[x][1],rk)+(b[x]?num[x]:0)+s[c[x][0]];
    }
    void dfs(int x)
    {
        if(c[x][0]) dfs(c[x][0]);
        if(b[x])q[++top]=x;
        if(c[x][1]) dfs(c[x][1]);
    }
    void build(int&x,int l,int r,int last)
    {
        if(l>r){x=0;return;}
        int mid=l+r>>1;x=q[mid];fa[x]=last;
        build(c[x][0],l,mid-1,x);
        build(c[x][1],mid+1,r,x);
        update(x);
    }
    void rebuild(int num)
    {
        int y=fa[mark];top=0;dfs(mark); 
        if(!y)build(rt[num],1,top,0);
        else build(c[y][c[y][1]==mark],1,top,y);
        mark=0;
    }
    int aska(int x,int k)
    {
        if(!x) return 0;
        if(k>=nn[x]) return size[c[x][0]]+b[x]+aska(c[x][1],k);
        return aska(c[x][0],k);     
    }
    int askb(int x,int k)
    {
        if(!x) return 0;
        if(k>nn[x]) return askb(c[x][1],k);
        return size[c[x][1]]+b[x]+askb(c[x][0],k);
    }
    int GetMax(int x,int l,int r,int lt,int rt)
    {
         if(!x||l>r||!r)return 0;
         if(l==lt&&r==rt)return mx[x];
         if(b[x])
         {
              int mid=size[c[x][0]]+lt;
              if(r<mid) return GetMax(c[x][0],l,r,lt,mid-1);
              else if(l>mid) return GetMax(c[x][1],l,r,mid+1,rt);
              else
              {
                   int mx=max(GetMax(c[x][0],l,mid-1,lt,mid-1),GetMax(c[x][1],mid+1,r,mid+1,rt)); 
                   if(l<=mid&&mid<=r) mx=max(mx,num[x]);
                   return mx;
              }
         }
         else
         {
              int mid=size[c[x][0]]+lt-1;
              if(r<=mid) return GetMax(c[x][0],l,r,lt,mid);
              else if(l>mid) return GetMax(c[x][1],l,r,mid+1,rt);
              else return max(GetMax(c[x][0],l,mid,lt,mid),GetMax(c[x][1],mid+1,r,mid+1,rt));   
         }
    }
    int getmax(int x,int l,int r)
    {
        int lt=aska(rt[x],l-1)+1;int rl=size[rt[x]]-askb(rt[x],r+1);
        lt=max(lt,1LL);rl=min(rl,size[rt[x]]);if(lt>rl)return 0;
        return GetMax(rt[x],lt,rl,1,size[rt[x]]);
    }
    void modify(int x,int k,int ad)
    {
        if(nn[x]==k&&b[x]) {num[x]=ad;update(x);return;}
        modify(c[x][k>nn[x]],k,ad);update(x);
    }
    #undef MN
}
 
namespace TREE
{
    #define MN 200000
    struct edge{int to,next;}e[MN*2+5];
    int fa[MN+5],top[MN+5],size[MN+5],mx[MN+5],cnt=0,head[MN+5],nl[MN+5],nr[MN+5],dfn=0,dep[MN+5];
    void ins(int f,int t)
    {
        e[++cnt]=(edge){t,head[f]};head[f]=cnt;
        e[++cnt]=(edge){f,head[t]};head[t]=cnt;
    }
    void dfs1(int x,int f)
    {
        fa[x]=f;size[x]=1;
        for(int i=head[x];i;i=e[i].next)    
            if(e[i].to!=f)
            {
                dep[e[i].to]=dep[x]+1;dfs1(e[i].to,x);size[x]+=size[e[i].to];
                if(size[e[i].to]>size[mx[x]]) mx[x]=e[i].to;
            }
    } 
    void dfs2(int x,int tp)
    {
        nl[x]=++dfn;top[x]=tp;
        if(mx[x]) dfs2(mx[x],tp);
        for(int i=head[x];i;i=e[i].next) 
            if(e[i].to!=fa[x]&&e[i].to!=mx[x])
                dfs2(e[i].to,e[i].to);
        nr[x]=dfn;
    }
    #undef MN
}
 
#define MN 200000
int n,m,s[MN+5],kind[MN+5];
char op;
 
void solve_sum(int x,int y)
{
    using namespace TREE;
    int sum=0,k=kind[x];
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        sum+=SGT::query(SGT::rt[k],nl[x])-SGT::query(SGT::rt[k],nl[top[x]]-1);
        x=fa[top[x]];
    }
    if(dep[x]<dep[y]) swap(x,y);
    sum+=SGT::query(SGT::rt[k],nl[x]);sum-=SGT::query(SGT::rt[k],nl[y]-1);
    printf("%d\n",sum);
}
 
void solve_max(int x,int y)
{
    using namespace TREE;
    int mx=0,k=kind[x];
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        mx=max(mx,SGT::getmax(k,nl[top[x]],nl[x]));
        x=fa[top[x]];
    }
    if(dep[x]<dep[y]) swap(x,y);
    mx=max(mx,SGT::getmax(k,nl[y],nl[x]));
    printf("%d\n",mx);
}
 
main()
{
    fread(B,1,1<<25,stdin);
    n=read();m=read();
    for(int i=1;i<=n;i++)
        s[i]=read(),kind[i]=read();
    for(int i=1;i<n;i++)
    {
        int u=read(),v=read();
        TREE::ins(u,v);
    }
    TREE::dfs1(1,0);TREE::dfs2(1,1);
    for(int i=1;i<=n;i++)
    {
        SGT::ins(SGT::rt[kind[i]],TREE::nl[i],s[i],0);
        if(SGT::mark) SGT::rebuild(kind[i]);
    }       
    for(int i=1;i<=m;i++)
    {
        do op=getc(); while(op<'A'||op>'Z');
        op=getc();int l=read(),r=read();
        if(op=='S') solve_sum(l,r);
        if(op=='M') solve_max(l,r);
        if(op=='C') 
        {   
            if(kind[l]==r) continue;
            SGT::del(SGT::rt[kind[l]],TREE::nl[l]);SGT::ins(SGT::rt[kind[l]=r],TREE::nl[l],s[l],0);
            if(SGT::mark) SGT::rebuild(kind[l]);                        
        }
        if(op=='W') SGT::modify(SGT::rt[kind[l]],TREE::nl[l],s[l]=r);
    }
    return 0;
}

 

FallDream代表秋之国向您问好! 欢迎您来我的博客www.cnblogs.com/FallDream
posted @ 2017-03-29 19:45  FallDream  阅读(198)  评论(0编辑  收藏  举报