BZOJ[1984]月下“毛景树” 树链剖分+线段树

21 篇文章 0 订阅
9 篇文章 0 订阅

传送门ber~

边权放到下面的点上,统计/修改时不算他俩的LCA
Add时:
①上面已经有覆盖标记——覆盖标记+k
②没有覆盖标记——加标记+k
覆盖时
①上面已经有加标记——加标记清零,覆盖标记打上
①上面没有加标记——加标记清零,覆盖标记打上…

代码如下:

#include<algorithm>
#include<ctype.h>
#include<cstdio>
#define N 100020
using namespace std;
const int base=-2147483647;
inline int read(){
    int x=0,f=1;char c;
    do c=getchar(),f=c=='-'?-1:f; while(!isdigit(c));
    do x=(x<<3)+(x<<1)+c-'0',c=getchar(); while(isdigit(c));
    return x*f;
}
int n,x,y,k,Top,T;
int w[N],pre[N],tree[N],fa[N],dep[N],son[N],top[N],fir[N],siz[N];
char c[15];
struct Edge{
    int to,nex,k;
    Edge(int _=0,int __=0,int ___=0):to(_),nex(__),k(___){}
}nex[N<<1];
struct Table{
    int x,y,k;
}a[N];
struct Node{
    int l,r,addv,v;
    int maxx;
    Node *ls,*rs;
    inline void maintain(){
        if(l==r) return;
        maxx=max(ls->maxx,rs->maxx);
    }
    inline void Pushdown(){
        if(l==r) return;
        if(v!=base){
            ls->v=v;ls->maxx=v;
            rs->v=v;rs->maxx=v;
            addv=0;v=base;
            return;
        }
        else if(addv){
            ls->maxx+=addv;
            if(ls->v!=base) ls->v+=addv;
            ls->addv+=addv;
            rs->maxx+=addv;
            if(rs->v!=base) rs->v+=addv;
            rs->addv+=addv;
            addv=0;v=base;
            return;
        }
    }
}*root;
inline void add(int x,int y,int k){
    nex[++Top]=Edge(y,fir[x],k);
    fir[x]=Top;
}
void dfs1(int x,int Dep,int Fa){
    fa[x]=Fa;dep[x]=Dep;
    siz[x]=1;
    for(int i=fir[x];i;i=nex[i].nex){
        if(nex[i].to==Fa) continue;
        dfs1(nex[i].to,Dep+1,x);
        w[nex[i].to]=nex[i].k;
        siz[x]+=siz[nex[i].to];
        if(siz[nex[i].to]>siz[son[x]]) son[x]=nex[i].to;
    }
}
void dfs2(int x,int Top){
    top[x]=Top;
    tree[x]=++T;pre[T]=x;
    if(!son[x]) return;
    dfs2(son[x],Top);
    for(int i=fir[x];i;i=nex[i].nex){
        if(nex[i].to==fa[x] || nex[i].to==son[x]) continue;
        dfs2(nex[i].to,nex[i].to);
    }
}
void maketree(int l,int r,Node *k){
    k->l=l;k->r=r;
    k->v=base;k->addv=0;
    if(l==r){
        k->maxx=w[pre[l]];
        return;
    }
    int mid=l+r>>1;
    maketree(l,mid,k->ls=new Node);maketree(mid+1,r,k->rs=new Node);
    k->maintain();
}
void Add(int l,int r,int x,Node *k){
    if(k->l>=l && k->r<=r){
        if(k->v!=base)
            k->v+=x;
        else k->addv+=x;
        k->maxx+=x;
        return;
    }
    int mid=k->l+k->r>>1;
    k->Pushdown();
    if(r<=mid) Add(l,r,x,k->ls);
    else if(l>mid) Add(l,r,x,k->rs);
    else Add(l,r,x,k->ls),Add(l,r,x,k->rs);
    k->maintain();
}
void Modify(int l,int r,int x,Node *k){
    if(k->l>=l && k->r<=r){
        k->v=x;k->addv=0;
        k->maxx=x;
        return;
    }
    int mid=k->l+k->r>>1;
    k->Pushdown();
    if(r<=mid) Modify(l,r,x,k->ls);
    else if(l>mid) Modify(l,r,x,k->rs);
    else Modify(l,r,x,k->ls),Modify(l,r,x,k->rs);
    k->maintain();
}
int Query_Max(int l,int r,Node *k){
    if(k->l>=l && k->r<=r){
        return k->maxx;
    }
    k->Pushdown();
    int mid=k->l+k->r>>1,t;
    if(r<=mid) t=Query_Max(l,r,k->ls);
    else if(l>mid) t=Query_Max(l,r,k->rs);
    else t=max(Query_Max(l,r,k->ls),Query_Max(l,r,k->rs));
    return t;
}
inline void Modify_Tree(int x,int y,int k){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        Modify(tree[top[x]],tree[x],k,root);
        x=fa[top[x]];
    }
    if(x==y) return;
    if(tree[x]>tree[y]) swap(x,y);
    Modify(tree[x]+1,tree[y],k,root);
}
inline void Add_Tree(int x,int y,int k){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        Add(tree[top[x]],tree[x],k,root);
        x=fa[top[x]];
    }
    if(x==y) return;
    if(tree[x]>tree[y]) swap(x,y);
    Add(tree[x]+1,tree[y],k,root);
}
inline int Max_Tree(int x,int y){
    int maxx=base;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        maxx=max(maxx,Query_Max(tree[top[x]],tree[x],root));
        x=fa[top[x]];
    }
    if(x==y) return maxx;
    if(tree[x]>tree[y]) swap(x,y);
    maxx=max(maxx,Query_Max(tree[x]+1,tree[y],root));
    return maxx;
}
inline void Debug1(){
    printf("\nTree Pow:\n\n");
    for(int i=1;i<=n;i++){
        printf("id:%d  tree:%d  son:%d  siz:%d  top:%d\n",i,tree[i],son[i],siz[i],top[i]);
    }
    for(int i=1;i<=n;i++) printf("%d ",pre[i]);
    printf("\nTree Pow End.\n\n");
}
void dfs(Node *x){
    if(!x) return;
    x->Pushdown();
    printf("l:%d r:%d   v:%d  addv:%d    maxx:%d\n",x->l,x->r,x->v,x->addv,x->maxx);
    dfs(x->ls);dfs(x->rs);
}
inline void Debug2(){
    printf("\nSegment Tree:\n\n");
    dfs(root);
    printf("\n\n");
}
int main(){
    n=read();
    for(int i=1;i<n;i++){
        x=read();y=read();k=read();
        a[i].x=x;a[i].y=y;a[i].k=k;
        add(x,y,k);add(y,x,k);
    }
    dfs1(1,1,0);dfs2(1,1);
    maketree(1,n,root=new Node);
    while(""){
        scanf("%s",c+1);
        if(c[1]=='C'){
            if(c[2]=='o'){
                x=read();y=read();k=read();
                Modify_Tree(x,y,k);
            }
            else{
                x=read();k=read();
                y=a[x].y;x=a[x].x;
                if(dep[x]<dep[y]) swap(x,y);
                Modify(tree[x],tree[x],k,root);
            }
        }
        else if(c[1]=='A'){
            x=read();y=read();k=read();
            Add_Tree(x,y,k);
        }
        else if(c[1]=='M'){
            x=read();y=read();
            printf("%d\n",Max_Tree(x,y));
        }
        else break;
    }
return 0;
}

这里写图片描述
sb才这么写调半天
想骂人

附上一组小数据生成器:

#include<bits/stdc++.h>
#define random(a,b) ((a)+rand()%((b)-(a)+1))
using namespace std;
const int N=10;
const int M=15;
stringstream str;
int x,y,n,m,t,seed;
int f[N];
int find(int x){return f[x]==x?f[x]:f[x]=find(f[x]);}
int main(int argc,char *argv[]){
    seed=time(NULL);
    if(argc){
        str.clear();
        str<<argv[1];
        str>>seed;
    }
    srand(seed);
    n=random(1,N);
    for(int i=1;i<=n;i++) f[i]=i;
    printf("%d\n",n);
    for(int cnt=1;cnt<n;){
        x=rand()%n+1;y=rand()%n+1;
        int fx=find(x),fy=find(y);
        if(fx==fy){continue;}
        f[fy]=fx;
        printf("%d %d",x,y);
        printf(" %d",rand()%10+1);
        puts("");
        cnt++;
    }
    m=rand()%10;
    for(int i=1;i<=m;i++){
        t=rand()%4+1;
        if(t==1){
            printf("Change %d %d\n",rand()%(n-1)+1,rand()%10+1);
        }
        else if(t==2){
            do x=rand()%n+1,y=rand()%n+1; while(x==y);
            printf("Cover %d %d %d\n",x,y,rand()%10+1);
        }
        else if(t==3){
            do x=rand()%n+1,y=rand()%n+1; while(x==y);
            printf("Max %d %d\n",x,y);
        }
        else if(t==4){
            do x=rand()%n+1,y=rand()%n+1; while(x==y);
            printf("Add %d %d %d\n",x,y,rand()%10+1);
        }
    }
    printf("Stop");
return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值