[BZOJ4551][JZOJ4604]【TJOI&HEOI2016】D1T1 树

来源:互联网 发布:ubuntu怎么连接wifi 编辑:程序博客网 时间:2024/05/16 08:03

Description

在2016年,佳媛姐姐刚刚学习了树,非常开心。
现在他想解决这样一个问题:
给定一颗有根树(根为1),有以下两种操作:
1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均无标记,而且对于某个结点,可以打多次标记。)
2. 询问操作:询问某个结点最近的一个打了标记的祖先(这个结点本身也算自己的祖
先)你能帮帮他吗?

Solution

这题至少有两种解法。

  • 解法1:可以离线处理。把每个操作读入后倒序,就变成了删除节点,也就是合并联通块。这样完全可以用并查集完成。
  • 解法2:如果一定要在线的话。可以用树链剖分,每个询问就是要求1~x的路径上最深的有标记的点。显然这里DFS序越大深度越大。修改就是把这个点改成它的DFS序,线段树维护最大值即可。

解法1的复杂度是O(N+qα(N)),码量个人认为1K左右
解法2的复杂度是O(Nlog2N),码量2.7K~~

然而比赛的时候,本人对自己的代码能力十分自信,机(sha)智(bi)的打了解法2。
结果一直拍到11:00

Code

下面是比赛时候打的链剖~

#include<cstdio>#include<cstdlib>#include<cmath>#include<cstring>#include<algorithm>#include<iostream>#define fo(i,a,b) for(i=a;i<=b;i++)#define fod(i,a,b) for(i=a;i>=b;i--)#define MAXN 100005using namespace std;struct note{    int mx,ls,rs;   }tree[2000005];struct rd{    int x,y;}a[MAXN];int top[MAXN],size[MAXN],son[MAXN],dfn[MAXN],pt[MAXN],ft[MAXN],deep[MAXN],n,m,a1[MAXN][2],df,num;bool cmp(rd x,rd y){    return x.x<y.x;}void dfs1(int k){    int i,mx=0;    if (a1[k][0]!=0)    fo(i,a1[k][0],a1[k][1])    {        dfs1(a[i].y);        size[k]+=size[a[i].y];        if (size[a[i].y]>mx)         {            son[k]=a[i].y;            mx=size[a[i].y];        }    }    size[k]++;}void dfs2(int k){    int i;    dfn[k]=++df;    pt[df]=k;    if (son[k]!=0)    {        top[son[k]]=top[k];        dfs2(son[k]);    }    if (a1[k][0]!=0)     fo(i,a1[k][0],a1[k][1])    {        if(a[i].y==son[k]) continue;        top[a[i].y]=a[i].y;        dfs2(a[i].y);    }}int find(int now,int l,int r,int x,int y){    if (now==0) return 0;    int ls=tree[now].ls,rs=tree[now].rs;    if (l==x&&r==y) return tree[now].mx;     int mid=(l+r)/2;    if (y<=mid) return find(ls,l,mid,x,y);    else if(x>mid) return find(rs,mid+1,r,x,y);    else return max(find(ls,l,mid,x,mid),find(rs,mid+1,r,mid+1,y));}void change(int now,int l,int r,int x,int y,int v){    int ls=tree[now].ls,rs=tree[now].rs;    if (l==x&&r==y)     {        tree[now].mx=v;        return;    }    int mid=(l+r)/2;     if (ls==0) ls=tree[now].ls=++num,tree[ls].mx=0;    if (rs==0) rs=tree[now].rs=++num,tree[rs].mx=0;    if (y<=mid) change(ls,l,mid,x,y,v);     else if(x>=mid) change(rs,mid+1,r,x,y,v);    else change(ls,l,mid,x,mid,v),change(rs,mid+1,r,mid+1,y,v);    tree[now].mx=max(tree[ls].mx,tree[rs].mx);}int ask(int x,int y){    int fx=top[x],fy=top[y];    if (fx==fy)     {        if (deep[x]>deep[y]) swap(x,y);        return find(1,1,n,dfn[x],dfn[y]);    }    else     {        if (deep[fx]<deep[fy]) swap(fx,fy),swap(x,y);        return max(find(1,1,n,dfn[fx],dfn[x]),ask(ft[fx],y));    }}int main(){    cin>>n>>m;    int i,j,k;    deep[1]=1;    memset(size,0,sizeof(size));    df=0;    fo(i,1,n-1)     {        int x,y;        scanf("%d%d",&x,&y);        ft[y]=x;        deep[y]=deep[x]+1;        a[i].x=x;        a[i].y=y;    }    sort(a+1,a+n,cmp);    fo(i,1,n-1)    {        if (a[i].x!=a[i-1].x)        {            a1[a[i].x][0]=i;            a1[a[i-1].x][1]=i-1;        }     }    a1[a[n-1].x][1]=n-1;    top[1]=1;    dfs1(1);    dfs2(1);    num=1;    change(1,1,n,1,1,1);     int pq=0;    fo(i,1,m)    {        char ch;        scanf("\n");        scanf("%c%d",&ch,&k);        if (ch=='Q') printf("%d\n",pt[ask(1,k)]);        else change(1,1,n,dfn[k],dfn[k],dfn[k]);     } } 
0 0
原创粉丝点击