【GDSOI2017】中学生数据结构题

来源:互联网 发布:sql课程设计说明书模板 编辑:程序博客网 时间:2024/04/24 20:04

Description

这里写图片描述

Input

第一行有一个整数 N,表示 S 国城市的数量。
接下来有 N-1 行,每行两个数 u,v 表示一条道路。
第 N+1 行为一个整数 Q,表示接下来有 Q 个操作。
接下来有 Q 行,每行表示一个操作,格式如题目描述所示。

Output

对于每一个 QUERY 操作,输出一个数,表示询问的当前编号为 X 和编号为 Y 的城市的最短路径间的城市 (包括编号为 X 的城市和编号为 Y 的城市)的士兵总和。

Sample Input

Sample Input1:
5
1 2
1 3
3 4
3 5
6
ADD 1 5 2
ADD 3 4 1
QUERY 1 4
SHIFT 1 4
ADD 5 4 1
QUERY 4 5

Sample Input12:
5
1 2
2 3
3 4
4 5
5
ADD 1 3 2
ADD 3 5 1
SHIFT 2 4
QUERY 1 3
QUERY 1 5

Solution

GDOI必有一题数据结构防AK题
此题有两种解法

第一种

(我不是用的这种)
这种方法思考和实现起来比较简单,细节也比较少,但是码量比第二种大,大概5000~6000Byte

用树链剖分和splay来维护,对于每一个重链和每一个轻边建一颗splay
add和query很简单,用常规的树链剖分做法做就行了
shift操作在两颗splay中间时要注意,把前面的最后一个点接到后面的第一个点之前,再把最前面和最后面的splay维护一下即可

第二种

(我用的是这种方法)
用LCT维护
shift操作时要断点和连点,所以splay会被破坏,所以要两棵LCT
一棵是编号LCT,一棵是权值LCT
在makeroot,access等时,编号LCT的编号是固定的,可直接使用
在access的时候,splay的形态会改变,同时要保证两棵LCT形态完全相同
在add,shift,query时,找到编号LCT中某个点对应在权值LCT中的点,然后求值
那么怎样找编号LCT中某个点对应的权值LCT中的点呢?
需要记录下编号LCT中的每棵splay的根对应的权值LCT中的每棵splay的根是哪一个,反过来也需要记录下来,这个只用在access和rotate的时候维护
因为两棵LCT形态相同,所以中序遍历的点是相同的
所有找对应点时,利用编号LCT中点的位置,通过中序遍历找到权值LCT对应的点
然后就愉快的码吧

Code

#include<cstdio>#include<cstring>#include<algorithm>#define N 101000#define fo(i,a,b) for(int i=a;i<=b;i++)#define ll long longusing namespace std;int p[N],fa[2][N],t[2][N][2],rev[2][N],n,root[2][N],s[N];ll lz[N],sum[N],d[N],size[2][N];int lr(int qq,int x){return x==t[qq][fa[qq][x]][1];}void down(int qq,int x){    if(rev[qq][x])    {        swap(t[qq][x][0],t[qq][x][1]);        rev[qq][t[qq][x][0]]^=1;rev[qq][t[qq][x][1]]^=1;        rev[qq][x]=0;    }    if(qq==1)    {        if(lz[x])        {            if(t[1][x][0]) d[t[1][x][0]]+=lz[x],sum[t[1][x][0]]+=lz[x]*size[1][t[1][x][0]],lz[t[1][x][0]]+=lz[x];            if(t[1][x][1]) d[t[1][x][1]]+=lz[x],sum[t[1][x][1]]+=lz[x]*size[1][t[1][x][1]],lz[t[1][x][1]]+=lz[x];            lz[x]=0;        }    }}int kth(int r,int x){    down(1,r);    if(x==size[1][t[1][r][0]]+1) return r;    if(x<=size[1][t[1][r][0]]) return kth(t[1][r][0],x);    else return kth(t[1][r][1],x-size[1][t[1][r][0]]-1);}void update(int qq,int x){    size[qq][x]=size[qq][t[qq][x][0]]+size[qq][t[qq][x][1]]+1;    if(qq==1) sum[x]=sum[t[1][x][0]]+sum[t[1][x][1]]+d[x];}void rotate(int qq,int x){    int y=fa[qq][x],k=lr(qq,x);    t[qq][y][k]=t[qq][x][1-k];if(t[qq][x][1-k]) fa[qq][t[qq][x][1-k]]=y;    fa[qq][x]=fa[qq][y];    if(fa[qq][y]) t[qq][fa[qq][y]][lr(qq,y)]=x;    else     {        root[qq][x]=root[qq][y];root[1-qq][root[qq][y]]=x;        if(qq==0) p[x]=p[y],p[y]=0;    }    fa[qq][y]=x;t[qq][x][1-k]=y;    update(qq,y);update(qq,x);}void xc(int qq,int x){    for(;x;x=fa[qq][x]) s[++s[0]]=x;    for(;s[0];s[0]--) down(qq,s[s[0]]);}void splay(int qq,int x,int y){    xc(qq,x);    while(fa[qq][x]!=y)    {        if(fa[qq][fa[qq][x]]!=y)            if(lr(qq,x)==lr(qq,fa[qq][x])) rotate(qq,fa[qq][x]);            else rotate(qq,x);        rotate(qq,x);    }}int get(int x){    splay(1,root[0][x],0);    return kth(root[0][x],size[0][t[0][x][0]]+1);}void access(int x){    int y=0,yy=0;    while(x>0)    {        splay(0,x,0);        int xx=get(x);        splay(1,xx,0);        fa[0][t[0][x][1]]=0;p[t[0][x][1]]=x;        fa[1][t[1][xx][1]]=0;        root[0][t[0][x][1]]=t[1][xx][1];        root[1][t[1][xx][1]]=t[0][x][1];        t[0][x][1]=y;        t[1][xx][1]=yy;        fa[0][y]=x;p[y]=0;        fa[1][yy]=xx;        update(0,x);update(1,xx);        y=x;x=p[x];yy=xx;    }}void makeroot(int x){    access(x);    splay(0,x,0);    rev[0][x]^=1;    int xx=get(x);    splay(1,xx,0);    rev[1][xx]^=1;}void link(int x,int y){    makeroot(x);p[x]=y;}int main(){    freopen("shift.in","r",stdin);    freopen("shift.out","w",stdout);    scanf("%d",&n);    fo(i,1,n) root[0][i]=root[1][i]=i;    fo(i,1,n-1)    {        int x,y;scanf("%d%d",&x,&y);        link(x,y);    }    int ac;scanf("%d\n",&ac);    for(;ac;ac--)    {        char ch;scanf("%c",&ch);        int x,y;ll z;        if(ch=='A')        {            scanf("DD%d%d%d\n",&x,&y,&z);            makeroot(x);            access(y);            splay(0,x,0);            int x1=get(x);            splay(1,x1,0);            d[x1]+=z;sum[x1]+=z*size[1][x1];lz[x1]+=z;        }        if(ch=='S')        {            scanf("HIFT%d%d\n",&x,&y);            if(x==y) continue;            makeroot(x);access(y);            splay(0,x,0);            int xx=get(x);            splay(0,y,0);            int yy=get(y);            splay(1,yy,0);fa[1][t[1][yy][0]]=0,t[1][yy][0]=0;            splay(1,xx,0);fa[1][t[1][yy][1]=xx]=yy,root[0][y]=yy;        }        if(ch=='Q')        {            scanf("UERY%d%d\n",&x,&y);            makeroot(x);access(y);            splay(0,x,0);            int x1=get(x);            splay(1,x1,0);            printf("%lld\n",sum[x1]);        }    }}
原创粉丝点击