BZOJ 3083 树链剖分+倍增+线段树

思路:
先随便选个点 链剖+线段树
1操作 就直接改root变量的值
2操作 线段树上改
3操作
分成三种情况
1.new root = xx 整个子树的min就是ans
2. lca(new root,xx) !=xx query 一下 当前的标号 和当前的标号+size(链剖不就是个特殊的dfs序嘛)
3. lca(new root,xx) =xx 找一下root在xx的哪个子树里 这个子树的补集就是解了

好多题解写得是有问题的
他们找root在xx的哪个子树里 这个操作是暴力找的 会被菊花图卡
(所以我就又写了个倍增)

后附 对拍程序 (这玩意儿一遍AC真是幻想 啊……)

//By SiriusRen33333333333333
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 222222
int n,m,op,xx,yy,zz,v[N],next[N],first[N],tot,wei[N],tree[N*8],lazy[N*8];
int size[N],son[N],fa[N],deep[N],top[N],change[N],cnt,root,f[N][20],rev[N];
void add(int x,int y){v[tot]=y,next[tot]=first[x],first[x]=tot++;}
void dfs(int x){
    size[x]=1;
    for(int i=1;i<=19;i++)if((1<<i)<=deep[x])f[x][i]=f[f[x][i-1]][i-1];else break;
    for(int i=first[x];~i;i=next[i])if(v[i]!=fa[x]){
        fa[v[i]]=f[v[i]][0]=x,deep[v[i]]=deep[x]+1,dfs(v[i]);
        size[x]+=size[v[i]];
        if(size[son[x]]<size[v[i]])son[x]=v[i];
    }
}
void dfs2(int x,int tp){
    change[x]=++cnt,rev[cnt]=x,top[x]=tp;
    if(son[x])dfs2(son[x],tp);
    for(int i=first[x];~i;i=next[i])
        if(v[i]!=fa[x]&&v[i]!=son[x])
            dfs2(v[i],v[i]);
}
void push_down(int pos){lazy[pos<<1]=lazy[pos<<1|1]=tree[pos<<1]=tree[pos<<1|1]=lazy[pos];lazy[pos]=-1;}
void build(int l,int r,int pos){
    if(l==r){tree[pos]=wei[rev[l]];return;}
    int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;
    build(l,mid,lson),build(mid+1,r,rson);
    tree[pos]=min(tree[lson],tree[rson]);
}
void insert(int l,int r,int pos,int L,int R,int val){
    if(l>=L&&r<=R){tree[pos]=lazy[pos]=val;return;}
    if(~lazy[pos])push_down(pos);
    int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;
    if(mid<L)insert(mid+1,r,rson,L,R,val);
    else if(mid>=R)insert(l,mid,lson,L,R,val);
    else insert(l,mid,lson,L,R,val),insert(mid+1,r,rson,L,R,val);
    tree[pos]=min(tree[lson],tree[rson]);
}
int query(int l,int r,int pos,int L,int R){
    if(l>=L&&r<=R)return tree[pos];
    if(~lazy[pos])push_down(pos);
    int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;
    if(mid<L)return query(mid+1,r,rson,L,R);
    else if(mid>=R)return query(l,mid,lson,L,R);
    else return min(query(l,mid,lson,L,R),query(mid+1,r,rson,L,R));
}
void Change(int x,int y,int val){
    int fx=top[x],fy=top[y];
    while(fx!=fy){
        if(deep[fx]<deep[fy])swap(x,y),swap(fx,fy);
        insert(1,n,1,change[fx],change[x],val);
        x=fa[fx],fx=top[x];
    }if(deep[x]>deep[y])swap(x,y);
    insert(1,n,1,change[x],change[y],val);
}
int LCA(int x,int y){
    int fx=top[x],fy=top[y];
    while(fx!=fy){
        if(deep[fx]<deep[fy])swap(x,y),swap(fx,fy);
        x=fa[fx],fx=top[x];
    }return deep[x]>deep[y]?y:x;
}
int main(){
    memset(first,-1,sizeof(first)),memset(lazy,-1,sizeof(lazy));
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++)scanf("%d%d",&xx,&yy),add(xx,yy),add(yy,xx);
    for(int i=1;i<=n;i++)scanf("%d",&wei[i]);
    dfs(1),dfs2(1,1),build(1,n,1);
    scanf("%d",&root);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&op,&xx);
        if(op==1)root=xx;
        else if(op==2)scanf("%d%d",&yy,&zz),Change(xx,yy,zz);
        else{
            if(root==xx){printf("%d\n",tree[1]);continue;}
            int lca=LCA(xx,root);
            if(xx!=lca)printf("%d\n",query(1,n,1,change[xx],change[xx]+size[xx]-1));
            else{
                int tmp=deep[root]-deep[xx]-1,ans=0x3f3f3f3f;yy=root;
                for(int i=0;i<=19;i++)if((1<<i)&tmp)yy=f[yy][i];
                if(change[yy]>1)ans=query(1,n,1,1,change[yy]-1);
                if(change[yy]+size[yy]<=n)ans=min(ans,query(1,n,1,change[yy]+size[yy],n));
                printf("%d\n",ans);
            }
        }
    }
}

maker

//By SiriusRen
#include <ctime>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n=100000,m=100000,seed;
int main(){
    freopen("seed.txt","r",stdin);
    scanf("%d",&seed);
    srand(seed+time(0));rand();rand();rand();rand();rand();rand();rand();rand();
    freopen("seed.txt","w",stdout);
    printf("%d\n",seed);
    freopen("in.txt","w",stdout);
    printf("%d %d\n",n,m);
    for(int i=2;i<=n;i++)printf("%d %d\n",rand()%(i-1)+1,i);
    for(int i=1;i<=n;i++)printf("%d ",rand()+1);
    printf("\n%d\n",rand()%n+1);
    for(int i=1;i<=m;i++){
        int temp=rand();
        if(temp%3==0)printf("1 %d\n",rand()%n+1);
        else if(temp%3==1)printf("2 %d %d %d\n",rand()%n+1,rand()%n+1,rand()+1);
        else printf("3 %d\n",rand()%n+1);
    }
}

对拍:

//By SiriusRen
#include <ctime>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int cases;
int main(){
    while(1){
        printf("Case %d now~~~\n",++cases);
        system("mk.exe");
        int lasttime=clock();
        system("mine.exe<in.txt>out1.txt");
        printf("mine  time=%ld\n",clock()-lasttime);
        lasttime=clock();
        system("sol.exe<in.txt>out2.txt");
        printf("solution  time=%ld\n",clock()-lasttime);
        lasttime=clock();
        if(system("fc out1.txt out2.txt")){
            puts("Wrong Answer~~~");
            while(1);
        }
    }
}

这里写图片描述

posted @ 2017-01-06 14:18  SiriusRen  阅读(178)  评论(0编辑  收藏  举报