[HEOI2016/TJOI2016]树

原题

第一反应是dfs序+线段树,一个节点打上标记,就对整棵子树,下推标记时判断一下深度

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=100005;
struct egde {
    int t,next;
}e[N<<1];
struct tree {
    int ans;
}tr[N<<2];
int cnt,n,m,num;
int head[N],wei[N],law[N],dee[N];
void ans(int u,int t){
    e[++cnt].t=t;
    e[cnt].next=head[u];
    head[u]=cnt;
}
void build(int ts,int l,int r){
    tr[ts].ans=0;tr[ts].ans=1;
    if (l==r) return;
    int mid=(l+r)>>1;
    build(ts<<1,l,mid);
    build(ts<<1|1,mid+1,r);
}
void dfs(int u,int fa){
    wei[u]=++num;dee[u]=dee[fa]+1;;
    for (int i=head[u];i;i=e[i].next){
        int v=e[i].t;
        if (v==fa) continue;
        dfs(v,u);
    }
    law[u]=num;
}
int get(int x,int y){return dee[x]>dee[y]?x:y;}
void pushdown(int ts){
    if (!tr[ts].ans) return;
    int k=tr[ts].ans;tr[ts].ans=0;
    tr[ts<<1].ans=get(k,tr[ts<<1].ans);	
    tr[ts<<1|1].ans=get(k,tr[ts<<1|1].ans);
}
void update(int ts,int l,int r,int L,int R,int k){
    if (l==L && r==R) {
        tr[ts].ans=get(k,tr[ts].ans);
        return;
    }
    int mid=(l+r)>>1;
    pushdown(ts);
    if (L>mid) update(ts<<1|1,mid+1,r,L,R,k);
    else if (R<=mid) update(ts<<1,l,mid,L,R,k);
    else {
        update(ts<<1,l,mid,L,mid,k);update(ts<<1|1,mid+1,r,mid+1,R,k);
    }
}
int query(int ts,int l,int r,int k){
    if (l==r) return tr[ts].ans;
    int mid=(l+r)>>1;
    pushdown(ts);
    if (k<=mid) return query(ts<<1,l,mid,k);
    else return query(ts<<1|1,mid+1,r,k);
}
#define dd a=getchar()
void read(char &a,int &b){
    while(dd,a!='Q' && a!='C');
    scanf("%d",&b);
}
#undef dd
int main(){
//	freopen("hh.in","r",stdin);
    scanf("%d%d",&n,&m);
    for (int i=1;i<n;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        ans(a,b);ans(b,a);
    }
    dfs(1,0);
    update(1,1,n,1,n,1);
    for (int i=1;i<=m;i++){
        char a;int b;
        read(a,b);
        if (a=='Q') {
            printf("%d\n",query(1,1,n,wei[b]));
        }
        else {
            update(1,1,n,wei[b],law[b],b);
        }
    }
}

F2:并查集,逆序操作,有标记的节点的父亲是自己,不然是父亲节点。每次查询找祖先,消节点改变父亲

#include <cstdio>
using namespace std;
const int N=100005;
struct egde {
    int t,next;
}e[N<<1];
struct quer{
    int id,x;
}qu[N];
int cnt,n,m;
int head[N],mar[N],fa[N],f[N],ans[N];
void add(int u,int t){
    e[++cnt].t=t;
    e[cnt].next=head[u];
    head[u]=cnt;
}
void dfs(int u,int fa){
    f[u]=fa;
    for (int i=head[u];i;i=e[i].next){
        int v=e[i].t;
        if (v==fa) continue;
        dfs(v,u);
    }
}
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
#define dd a=getchar()
void read(char &a,int &b){
    while(dd,a!='Q' && a!='C');
    scanf("%d",&b);
}
#undef dd
int main(){
//	freopen("hh.in","r",stdin);
    scanf("%d%d",&n,&m);
    for (int i=1;i<n;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b);add(b,a);
    }
    dfs(1,1);mar[1]=1;
    for (int i=1;i<=m;i++){
        char a;int b;
        read(a,b);
        if (a=='Q') {
            qu[i].id=0;qu[i].x=b;
        }
        else {
        	mar[b]++;
            qu[i].id=1;qu[i].x=b;
        }
    }
    for (int i=1;i<=n;i++)
    	if (!mar[i]) fa[i]=f[i];
    		else fa[i]=i;
    for (int i=m;i>=1;i--){
    	if (!qu[i].id) {
    		ans[i]=find(qu[i].x);
        }
        else {
            mar[qu[i].x]--;
            if (!mar[qu[i].x]) fa[qu[i].x]=f[qu[i].x];
        }
    }
    for (int i=1;i<=m;i++)
        if (!qu[i].id)	printf("%d\n",ans[i]);
}

猜你喜欢

转载自blog.csdn.net/qq_41893580/article/details/79949121
今日推荐