• 线段树及其扩展


    板子:单点修改+区间查询

    #include<bits/stdc++.h>
    using namespace std;
    struct Tree
    {
        int l,r;
        int dat;
        #define l(x) tree[x].l;
        #define r(x) tree[x].r;
        #define d(x) tree[x].dat;
    }tree[N*4];
    void build(int p,int l,int r)
    {
        l(p)=l,r(p)=r;
        if(l==r) {d(p)=a[p];return;}
        int mid=(l+r)>>1;
        build(p<<1,l,mid);
        build(p<<1+1,mid+1,r);
        d(p)=max(d(p<<1),d(p<<1+1));
    }
    void change(int p,int x,int v)
    {
        if(l(p)==r(p)) {d(p)=v;return;}
        int mid=(l(p)+r(p))>>1;
        if(x<=mid) change(p<<1,x,v);
        else       change(p<<1+1,x,v);
        d(p)=max(d(p<<1),d(p<<1+1));
    }
    int ask(int p,int l,int r)
    {
        if(l<=l(p)&&r>=r(p)) return d(p);
        int mid=(l(p)+r(p))>>1;
        int val=-(1<<30);
        if(mid>=l) val=max(val,ask(p<<1,l,r));
        if(mid+1<=r) val=max(val,ask(p<<1+1,l,r));
        return val;
    }
    int main()
    {
        build(1,1,n);
        change(1,x,v);
        ask(1,1,n);
    } 
    View Code

    T1:求最大连续子段和(单点修改)

    //第一次认真的打线段树的板子....
    //第一次拼命wrong的点竟然在建树是的赋值,醉了醉了... 
    #include<bits/stdc++.h>
    using namespace std;
    const int N=500010;
    int n,T,c[N];
    struct Tree
    {
        int sum,dat,lmax,rmax,l,r;
        #define l(x) t[x].l
        #define r(x) t[x].r
        #define s(x) t[x].sum
        #define d(x) t[x].dat
        #define lm(x) t[x].lmax
        #define rm(x) t[x].rmax
    }t[N*4];
    inline int read()
    {
        int x=0,ff=1;
        char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        return x*ff;
    }
    inline void push(int p)
    {
        s(p)=s(p<<1)+s((p<<1)+1);
        lm(p)=max(lm(p<<1),s(p<<1)+lm((p<<1)+1));
        rm(p)=max(rm((p<<1)+1),s((p<<1)+1)+rm(p<<1));
        d(p)=max(max(d(p<<1),d((p<<1)+1)),rm(p<<1)+lm((p<<1)+1));
    }
    inline void build(int p,int l,int r)
    {
        l(p)=l,r(p)=r;
        if(l==r) {s(p)=d(p)=lm(p)=rm(p)=c[l(p)];return;}
        int mid=(l+r)>>1;
        build(p<<1,l,mid);
        build((p<<1)+1,mid+1,r);
        push(p);
    }
    inline void change(int p,int x,int v)
    {
        if(l(p)==r(p)) {s(p)=d(p)=lm(p)=rm(p)=v;return;}
        int mid=(l(p)+r(p))>>1;
        if(x<=mid) change(p<<1,x,v);
        else       change((p<<1)+1,x,v);
        push(p);
    }
    inline Tree ask(int p,int l,int r)
    {
        if(l<=l(p)&&r>=r(p)) return t[p];
        int mid=(l(p)+r(p))>>1;
        if(r<=mid) return ask(p<<1,l,r);
        else if(l>=mid+1) return ask((p<<1)+1,l,r);
        else 
        {
            Tree a,b,c;
            a=ask(p<<1,l,r);
            b=ask((p<<1)+1,l,r);
            c.sum=a.sum+b.sum;
            c.lmax=max(a.lmax,a.sum+b.lmax);
            c.rmax=max(b.rmax,b.sum+a.rmax);
            c.dat=max(max(a.dat,b.dat),a.rmax+b.lmax);
            return c;
        }
    }
    int main()
    {
        freopen("1.in","r",stdin);
        n=read();T=read();
        for(register int i=1;i<=n;++i) c[i]=read();
        build(1,1,n);
        while(T--)
        {
            int op=read(),x=read(),y=read();
            if(op==1) 
            {
                if(x>y) swap(x,y);
                printf("%d
    ",ask(1,x,y).dat);
            }
            else if(op==2) change(1,x,y);
        } 
        return 0;
    View Code

    板子:区间修改+区间查询.

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N=100010;
    int n,m,a[N];
    struct Tree
    {
        int l,r;
        ll sum,add;
        #define l(x) t[x].l
        #define r(x) t[x].r
        #define sum(x) t[x].sum
        #define add(x) t[x].add
    }t[N*4];
    inline int read()
    {
        int x=0,ff=1;
        char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        return x*ff;
    }
    inline void push(int p)
    {
        if(add(p))
        {
            sum(p<<1)+=(r(p<<1)-l(p<<1)+1)*add(p);
            sum((p<<1)+1)+=(r((p<<1)+1)-l((p<<1)+1)+1)*add(p);
            add(p<<1)+=add(p);
            add((p<<1)+1)+=add(p);
            add(p)=0;
        }
    }
    inline void build(int p,int l,int r)
    {
        l(p)=l,r(p)=r;
        if(l==r) {sum(p)=a[l];return;}
        int mid=(l+r)>>1;
        build(p<<1,l,mid);
        build((p<<1)+1,mid+1,r);
        sum(p)=sum(p<<1)+sum((p<<1)+1);
    } 
    inline void change(int p,int l,int r,ll d)
    {
        if(l<=l(p)&&r>=r(p)) 
        {
            sum(p)+=d*(r(p)-l(p)+1);
            add(p)+=d;
            return; 
        }
        push(p);
        int mid=(l(p)+r(p))>>1;
        if(mid>=l) change(p<<1,l,r,d);
        if(mid+1<=r) change((p<<1)+1,l,r,d);
        sum(p)=sum(p<<1)+sum((p<<1)+1); 
    }
    inline ll ask(int p,int l,int r)
    {
        if(l<=l(p)&&r>=r(p)) return sum(p);
        ll val=0;
        push(p);
        int mid=(l(p)+r(p))>>1;
        if(mid>=l) val+=ask(p<<1,l,r);
        if(mid+1<=r) val+=ask((p<<1)+1,l,r);
        return val;
    } 
    int main()
    {
        freopen("1.in","r",stdin);
        n=read();m=read();
        for(register int i=1;i<=n;++i) a[i]=read();
        build(1,1,n); 
        while(m--)
        {
            int op=read();
            if(op==1)
            {
                int x=read(),y=read(),k=read();
                change(1,x,y,k);
            }
            else 
            {
                int x=read(),y=read();
                printf("%lld
    ",ask(1,x,y));
            }
        }
        return 0;
    } 
    View Code

    T2:

    区间修改(+和*)+区间查询;

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N=500010;
    int n,m,P,a[N];
    struct Tree
    {
        int l,r;
        ll sum,add,mul;
        #define l(x) t[x].l
        #define r(x) t[x].r
        #define sum(x) t[x].sum
        #define add(x) t[x].add
        #define mul(x) t[x].mul
    }t[N*4];
    inline int read()
    {
        int x=0,ff=1;
        char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        return x*ff;
    }
    inline void push(int p)
    {
        if(mul(p)!=1)
        {
            sum(p<<1)=(sum(p<<1)*mul(p))%P;
            sum((p<<1)+1)=(sum((p<<1)+1)*mul(p))%P;
            add(p<<1)=(add(p<<1)*mul(p))%P;
            add((p<<1)+1)=(add((p<<1)+1)*mul(p))%P;
            mul(p<<1)=(mul(p<<1)*mul(p))%P;
            mul((p<<1)+1)=(mul((p<<1)+1)*mul(p))%P;
            mul(p)=1;
        }
        if(add(p))
        {
            sum(p<<1)=(sum(p<<1)+(r(p<<1)-l(p<<1)+1)*add(p))%P;
            sum((p<<1)+1)=(sum((p<<1)+1)+(r((p<<1)+1)-l((p<<1)+1)+1)*add(p))%P;
            add(p<<1)=(add(p<<1)+add(p))%P;
            add((p<<1)+1)=(add((p<<1)+1)+add(p))%P;
            add(p)=0;
        }
    }
    inline void build(int p,int l,int r)
    {
        l(p)=l,r(p)=r;mul(p)=1;
        if(l==r) {sum(p)=a[l];return;}
        int mid=(l+r)>>1;
        build(p<<1,l,mid);
        build((p<<1)+1,mid+1,r);
        sum(p)=(sum(p<<1)+sum((p<<1)+1))%P; 
    }
    inline void change1(int p,int l,int r,ll d)
    {
        if(l<=l(p)&&r>=r(p)) 
        {
            sum(p)=(sum(p)*d)%P;
            add(p)=(add(p)*d)%P;
            mul(p)=(mul(p)*d)%P;
            return;
        }
        push(p);
        int mid=(l(p)+r(p))>>1;
        if(l<=mid) change1(p<<1,l,r,d);
        if(r>=mid+1) change1((p<<1)+1,l,r,d);
        sum(p)=(sum(p<<1)+sum((p<<1)+1))%P;
    }
    inline void change2(int p,int l,int r,ll d)
    {
        if(l<=l(p)&&r>=r(p))
        {
            sum(p)=(sum(p)+(r(p)-l(p)+1)*d)%P;
            add(p)=(add(p)+d)%P;
            return;
        }
        push(p);
        int mid=(l(p)+r(p))>>1;
        if(l<=mid) change2(p<<1,l,r,d);
        if(r>=mid+1) change2((p<<1)+1,l,r,d);
        sum(p)=(sum(p<<1)+sum((p<<1)+1))%P;
    }
    inline ll ask(int p,int l,int r)
    {
        if(l<=l(p)&&r>=r(p)) return sum(p);
        push(p);
        int mid=(l(p)+r(p))>>1;
        ll val=0;
        if(l<=mid) val=(val+ask(p<<1,l,r))%P;
        if(r>=mid+1) val=(val+ask((p<<1)+1,l,r))%P;
        return val;
    }
    int main()
    {
        freopen("1.in","r",stdin);
        n=read();m=read();P=read();
        for(register int i=1;i<=n;++i) a[i]=read();
        build(1,1,n);
        while(m--)
        {
            int op=read();
            if(op==1) 
            {
                int x=read(),y=read(),k=read();
                change1(1,x,y,k);
            }
            else if(op==2)
            {
                int x=read(),y=read(),k=read();
                change2(1,x,y,k);
            }
            else if(op==3)
            {
                int x=read(),y=read();
                printf("%lld
    ",ask(1,x,y));
            }
        }
        return 0;
    } 
    View Code

     T3:区间最大公约数(单点修改)

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N=500010;
    ll n,T,a[N],c[N],b[N];
    struct Tree
    {
        ll l,r,dat;
        #define l(x) t[x].l
        #define r(x) t[x].r
        #define d(x) t[x].dat
    }t[N*4];
    inline ll read()
    {
        ll x=0,ff=1;
        char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        return x*ff;
    }
    ll lowbit(ll x) {return x&(-x);}
    inline void add(ll x,ll k) {for(;x<=n;x+=lowbit(x)) b[x]+=k;}
    inline ll assk(ll x)
    {
        ll ans=0;
        for(;x;x-=lowbit(x)) ans+=b[x];
        return ans;
    }
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    inline void build(ll p,ll l,ll r)
    {
        l(p)=l,r(p)=r;
        if(l==r) {d(p)=c[l];return;}
        ll mid=(l+r)>>1;
        build(p<<1,l,mid);
        build((p<<1)+1,mid+1,r);
        d(p)=gcd(d(p<<1),d((p<<1)+1));
    } 
    inline void change(ll p,ll x,ll v)
    {
        if(x>n) return;
        if(l(p)==r(p)) {d(p)+=v;return;}
        ll mid=(l(p)+r(p))>>1;
        if(x<=mid) change(p<<1,x,v);
        else       change((p<<1)+1,x,v);
        d(p)=gcd(d(p<<1),d((p<<1)+1));
    }
    inline ll ask(ll p,ll l,ll r)
    {
        if(l>r) return 0;     
        if(l<=l(p)&&r>=r(p)) return abs(d(p));
        ll mid=(l(p)+r(p))>>1;
        ll vl=0,vr=0;
        if(l<=mid) vl=ask(p<<1,l,r);
        if(r>=mid+1) vr=ask((p<<1)+1,l,r);
        return abs(gcd(vl,vr));
    }
    int main()
    {
        freopen("1.in","r",stdin);
        n=read();T=read();
        for(register int i=1;i<=n;++i) a[i]=read(),c[i]=a[i]-a[i-1];
        build(1,1,n);
        while(T--)
        {
            char ch;
            cin>>ch;if(ch=='C')
            {
                ll x=read(),y=read(),v=read();
                change(1,x,v);add(x,v);
                change(1,y+1,-v);add(y+1,-v);
            }
            else if(ch=='Q')
            {
                ll x=read(),y=read();
                printf("%lld
    ",gcd(a[x]+assk(x),ask(1,x+1,y)));
            }
        }
        return 0;
    } 
    View Code

     4:扫描线:

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N=1e5+10;
    double Y[N*2],x1,yy1,x2,y2;
    ll n,cnt;
    struct ScanLine
    {
        double l,r,x;
        int mark;
    }line[N*2];
    struct Tree
    {
        int l,r,sum;
        double len;
        #define l(p) t[p].l
        #define r(p) t[p].r
        #define sum(p) t[p].sum
        #define len(p) t[p].len
    }t[N<<3];
    inline bool cmp(ScanLine a,ScanLine b){return a.x<b.x;}
    inline void build(int p,int l,int r)
    {
        l(p)=l,r(p)=r;
        sum(p)=len(p)=0;
        if(l==r) return;
        int mid=(l+r)>>1;
        build(p<<1,l,mid);
        build((p<<1)+1,mid+1,r);
    }
    inline void push(int p)
    {
        if(sum(p)) len(p)=Y[r(p)+1]-Y[l(p)];
        else       len(p)=len(p<<1)+len((p<<1)+1); 
    }
    inline void change(int p,double l,double r,int c)
    {
        if(l<=Y[l(p)]&&r>=Y[r(p)+1]) 
        {
            sum(p)+=c;
            push(p);
            return;
        }
        ll mid=(l(p)+r(p))>>1;
        if(Y[mid]>=l) change(p<<1,l,r,c);
        if(Y[mid+1]<r) change((p<<1)+1,l,r,c);
        push(p);
    }
    int main()
    {
        freopen("1.in","r",stdin);
        while(cin>>n)
        {
            cnt++;
            if(n==0) break;
            for(register int i=1;i<=n;++i)
            {
                scanf("%lf %lf %lf %lf",&x1,&yy1,&x2,&y2);
                Y[i*2]=yy1;Y[i*2-1]=y2;
                line[i*2]=(ScanLine){yy1,y2,x1,1};
                line[i*2-1]=(ScanLine){yy1,y2,x2,-1};
            }
            n<<=1;
            sort(line+1,line+n+1,cmp);
            sort(Y+1,Y+n+1);
            int tot=unique(Y+1,Y+n+1)-Y-1;
            build(1,1,tot-1); 
            double ans=0;
            for(register int i=1;i<n;++i)
            {
                change(1,line[i].l,line[i].r,line[i].mark);
                ans+=len(1)*(line[i+1].x-line[i].x);
            }
            printf("Test case #%d
    ",cnt);
            printf("Total explored area: %.2lf
    
    ",ans);
        }
        return 0;
    }
    View Code

    最后记得一定要将i枚举到n,为了将线段树信息抵消...

    最近又做了巨多线段树的题:

    .....上次做完做鸡蛋后就对延迟标记的了解更深了....

    这个就是修改还行,直接就全部覆盖,至于每次查询,它问什么我们就求什么,我们保存每个区间的三个信息,区间内的最大连续空位,区间最靠左的连续空位,区间最靠右的连续空位.

    至于更新信息嘛就很简单了.最难的时查询时,我们一次考虑构成答案的三种情况.sum(p<<1),那就地柜左子树,sum(p<<1|1)你就递归右子树.rsum(p<<1)+lsum(p<<1|1)那就直接算答案.由于答案要求我们最小,所以我们搜索顺序就要调换一下...

    #include<bits/stdc++.h>
    using namespace std;
    const int N=50010;
    int n,m;
    struct Tree
    {
        int l,r,lsum,rsum,sum,add;
        #define lsum(x) t[x].lsum
        #define rsum(x) t[x].rsum
        #define l(x) t[x].l
        #define r(x) t[x].r
        #define sum(x) t[x].sum
        #define add(x) t[x].add
    }t[N<<2];
    inline int read()
    {
        int x=0,ff=1;
        char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        return x*ff;
    }
    inline void pushup(int p)
    {
        lsum(p)=lsum(p<<1);
        if(lsum(p<<1)==r(p<<1)-l(p<<1)+1) lsum(p)+=lsum(p<<1|1);
        rsum(p)=rsum(p<<1|1);
        if(rsum(p<<1|1)==r(p<<1|1)-l(p<<1|1)+1) rsum(p)+=rsum(p<<1);
        sum(p)=max(max(sum(p<<1),sum(p<<1|1)),rsum(p<<1)+lsum(p<<1|1));
    }
    inline void pushdown(int p)
    {   
        if(add(p)==1)
        {
            sum(p<<1)=lsum(p<<1)=rsum(p<<1)=r(p<<1)-l(p<<1)+1;
            sum(p<<1|1)=lsum(p<<1|1)=rsum(p<<1|1)=r(p<<1|1)-l(p<<1|1)+1;
            add(p<<1)=1;
            add(p<<1|1)=1;
            add(p)=0;
        }
        else if(add(p)==-1)
        {
            sum(p<<1)=lsum(p<<1)=rsum(p<<1)=0;
            sum(p<<1|1)=lsum(p<<1|1)=rsum(p<<1|1)=0;
            add(p<<1)=-1;
            add(p<<1|1)=-1;
            add(p)=0;
        }
    }
    inline void build(int p,int l,int r)
    {
        l(p)=l,r(p)=r;
        if(l==r) {sum(p)=rsum(p)=lsum(p)=1;return;}
        int mid=l+r>>1;
        build(p<<1,l,mid);
        build(p<<1|1,mid+1,r);
        pushup(p);
    }
    inline void alter(int p,int l,int r,int op)
    {
        if(l<=l(p)&&r>=r(p))
        {
            if(op==1)
            {
                sum(p)=lsum(p)=rsum(p)=r(p)-l(p)+1;
                add(p)=1;
            }
            else 
            {
                sum(p)=lsum(p)=rsum(p)=0;
                add(p)=-1;
            }
            return;
        }
        pushdown(p);
        int mid=l(p)+r(p)>>1;
        if(l<=mid) alter(p<<1,l,r,op);
        if(r>=mid+1) alter(p<<1|1,l,r,op);
        pushup(p);
    }
    inline int ask(int p,int x)
    {
        if(l(p)==r(p)) return l(p);
        pushdown(p);
        int mid=l(p)+r(p)>>1;
        if(sum(p<<1)>=x) return ask(p<<1,x);
        else if(rsum(p<<1)+lsum(p<<1|1)>=x) return mid-rsum(p<<1)+1;
        else if(sum(p<<1|1)>=x) return ask(p<<1|1,x);
    }
    int main()
    {
        n=read();m=read();
        build(1,1,n);
        for(int i=1;i<=m;++i)
        {
            int op=read();
            if(op==1)
            {
                int x=read();
                if(sum(1)>=x)
                {
                   int s=ask(1,x);
                   printf("%d
    ",s);
                   alter(1,s,s+x-1,-1);
                }
                else printf("0
    ");
            }
            else 
            {
                int x=read(),y=read();
                alter(1,x,x+y-1,1);
            }
        }
        return 0;
    }
    View Code

    疯狂的在推式子,结果需要暴力修改.

    因为每次的开跟,所以1e9最多开5次不变了,所以其实大部分的修改都是无效的.我们修改时就暴力修改子树,当子树修改时已经无影响时,我们打上标记,下次再修改时直接return即可...

    #include<bits/stdc++.h>
    #define ll long long 
    using namespace std;
    const int N=1e5+10;
    int n,a[N],m;
    struct Tree
    {
        int l,r;
        ll sum;
        bool vis;
        #define l(x) t[x].l
        #define r(x) t[x].r
        #define sum(x) t[x].sum
        #define vis(x) t[x].vis
    }t[N<<2];
    inline int read()
    {
        int x=0,ff=1;
        char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        return x*ff;
    }
    inline void build(int p,int l,int r)
    {
        l(p)=l,r(p)=r;
        if(l==r) 
        {
            sum(p)=a[l];
            if(sum(p)==0||sum(p)==1) vis(p)=1;
            return;
        }
        int mid=l+r>>1;
        build(p<<1,l,mid);
        build(p<<1|1,mid+1,r);
        sum(p)=sum(p<<1)+sum(p<<1|1);
        if(vis(p<<1)&&vis(p<<1|1)) vis(p)=1;
    }
    inline ll ask(int p,int l,int r)
    {
        if(l<=l(p)&&r>=r(p)) return sum(p);
        int mid=l(p)+r(p)>>1;
        ll ans=0;
        if(l<=mid) ans+=ask(p<<1,l,r);
        if(r>=mid+1) ans+=ask(p<<1|1,l,r);
        return ans;
    }
    inline void alter(int p,int l,int r)
    {
        if(l(p)==r(p)) 
        {
            sum(p)=sqrt(sum(p));
            if(sum(p)==0||sum(p)==1) vis(p)=1;
            return;
        }
        if(vis(p)) return;
        int mid=r(p)+l(p)>>1;
        if(l<=mid) alter(p<<1,l,r);
        if(r>=mid+1) alter(p<<1|1,l,r);
        sum(p)=sum(p<<1)+sum(p<<1|1);
        if(vis(p<<1)&&vis(p<<1|1)) vis(p)=1;
    }
    int main()
    {
        n=read();
        for(int i=1;i<=n;++i) a[i]=read();
        build(1,1,n);
        m=read();
        for(int i=1;i<=m;++i)
        {
            int op=read(),x=read(),y=read();
            if(op==1) printf("%lld
    ",ask(1,x,y));
            else      alter(1,x,y);
        }
        return 0;
    }
    View Code

    好吧,最后几道就压轴出场了:

    这道题真的想写很久了,前置知识一学完就又回来刚这道题...

    不过真的咋看不会,看的第一眼,嗯,树上差分,如果z值不大,那我们就可以轻松用数组搞定,之后用dfs合并输出,每次在一个点的cnt[x][z]中选出最大的一个点,这样的复杂度...emmm应该是(nz)的.不过不光是时间过不去,空间也开不下....

    之后我就翻开题解,一看他们全部都是权值线段树啊,啥主席树啊,在哪瞎搞,权值线段树我也懂,可为什么要用呢?我是真的不懂.....死劲看....也看不出来....

    终于我好像懂了点....权值线段树用数值存次数,简单地说就是一个桶...就像我们以前用的桶排序一样,既然数组开不下,我们完全可以用权值线段树代替,而且查询最大值还是log的

    其实仔细想想,没错啊!权值线段树不就只是用权值记录次数吗?我们要找的最大值不也是找所有的数中出现次数最多的吗?之后,就用权值线段树瞎搞....

    在合并时用上线段树合并...玄学复杂度....于是乎就这样水过了....不过最后wrong的一个点着实让人不满意...提醒我们权值线段树当出现次数为负值时,不可更新答案...

    怎么说呢....真的很高兴.....哈哈哈哈哈哈哈哈.....

    #include<bits/stdc++.h>
    using namespace std;
    const int N=100010,M=10000010;
    int n,m,link[N],tot,root[N],cnt;
    int deep[N],f[N][25],fa[N];
    struct edge{int y,next;}a[N<<1];
    struct Tree
    {
        int lc,rc,dat,mx;
        #define lc(x) t[x].lc
        #define rc(x) t[x].rc
        #define dat(x) t[x].dat
        #define mx(x) t[x].mx
    }t[M<<2];
    inline int read()
    {
        int x=0,ff=1;
        char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        return x*ff;
    }
    inline void add(int x,int y)
    {
        a[++tot].y=y;
        a[tot].next=link[x];
        link[x]=tot;
    }
    inline void bfs()
    {
        queue<int>q;q.push(1);
        deep[1]=1;
        while(!q.empty())
        {
            int x=q.front();q.pop();
            for(int i=link[x];i;i=a[i].next)
            {
                int y=a[i].y;
                if(deep[y]) continue;
                deep[y]=deep[x]+1;q.push(y);
                f[y][0]=x;fa[y]=x;
                for(int i=1;i<=20;++i) f[y][i]=f[f[y][i-1]][i-1];
             }
        }
    }
    inline int lca(int x,int y)
    {
        if(deep[x]<deep[y]) swap(x,y);
        for(int i=20;i>=0;--i) 
            if(deep[f[x][i]]>=deep[y]) x=f[x][i];
        if(x==y) return x;
        for(int i=20;i>=0;--i)
            if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
        return f[x][0];        
    }
    inline int build()
    {
        cnt++;
        lc(cnt)=rc(cnt)=dat(cnt)=0;
        return cnt;
    }
    inline void pushup(int p)
    {
        if(mx(lc(p))>=mx(rc(p))){mx(p)=mx(lc(p));dat(p)=dat(lc(p));}
        else{mx(p)=mx(rc(p));dat(p)=dat(rc(p));}
    }
    inline void alter(int p,int l,int r,int v,int k)
    {
        if(l==r) {mx(p)+=k;if(mx(p)>0) dat(p)=l;return;}
        int mid=l+r>>1;
        if(v<=mid)
        {
            if(!lc(p)) lc(p)=build();
            alter(lc(p),l,mid,v,k);
        }
        else 
        {
            if(!rc(p)) rc(p)=build();
            alter(rc(p),mid+1,r,v,k);
        }
        pushup(p);
    }
    inline int merge(int p,int q,int l,int r)
    {
        if(!p) return q;
        if(!q) return p;
        if(l==r)
        {
            mx(p)+=mx(q);
            if(mx(p)>0) dat(p)=l;
            return p;
        }
        int mid=l+r>>1;
        lc(p)=merge(lc(p),lc(q),l,mid);
        rc(p)=merge(rc(p),rc(q),mid+1,r);
        pushup(p);
        return p;
    }
    inline void dfs(int x)
    {
        for(int i=link[x];i;i=a[i].next)
        {
            int y=a[i].y;
            if(y==fa[x]) continue;
            dfs(y);
            root[x]=merge(root[x],root[y],1,N-1);
        }
    //    printf("x=%d dat(root[1])=%d
    ",x,dat(root[1]));
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        n=read();m=read();
        for(int i=1;i<n;++i)
        {
            int x=read(),y=read();
            add(x,y);add(y,x);
        }
        bfs();
        for(int i=1;i<=n;++i) root[i]=build();
        for(int i=1;i<=m;++i)
        {
            int x=read(),y=read(),z=read();                                
            int d=lca(x,y);                                    
            alter(root[x],1,N-1,z,1);                            
            alter(root[y],1,N-1,z,1);                          
            alter(root[d],1,N-1,z,-1);                               
            alter(root[fa[d]],1,N-1,z,-1);                        
        }
        dfs(1);
        for(int i=1;i<=n;++i) printf("%d
    ",dat(root[i]));
        return 0;
    } 
    View Code

    这个题,有一说一,确实是树剖的好题....

    则么说呢,感觉线段树维护的信息很显然..就是不知道讲树上的节点划分成若干个链后怎么统计答案....

    想不通....那只能在每次跳到fa[top[a]]时统计答案。

    具体的我们可以将这条链结束时,和即将跳的点颜色比较,因为这些节点就是这些链的分开的节点.....

    感觉和区间某些性质相关的题都可以这么做,就是在每次跳时都比较和父亲的属性是否相同.

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+10;
    int n,m,b[N],link[N],tot;
    int deep[N],fa[N],top[N],wson[N],dfn[N],pre[N],size[N],m1;
    struct edge{int y,next;}a[N<<1];
    struct Tree
    {
        int l,r,sum,lc,rc,lazy;
        #define l(x) t[x].l
        #define r(x) t[x].r
        #define sum(x) t[x].sum
        #define lc(x) t[x].lc
        #define rc(x) t[x].rc
        #define lazy(x) t[x].lazy
    }t[N<<2];
    inline int read()
    {
        int x=0,ff=1;
        char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        return x*ff;
    }
    inline void add(int x,int y)
    {
        a[++tot].y=y;
        a[tot].next=link[x];
        link[x]=tot;
    }
    inline void pushup(int p)
    {
        sum(p)=sum(p<<1)+sum(p<<1|1);
        if(rc(p<<1)==lc(p<<1|1)) sum(p)--;
        lc(p)=lc(p<<1);rc(p)=rc(p<<1|1);
    }
    inline void push(int p)
    {
        if(lazy(p))
        {
            sum(p<<1)=1;
            sum(p<<1|1)=1;
            lc(p<<1)=rc(p<<1)=lazy(p);
            lc(p<<1|1)=rc(p<<1|1)=lazy(p);
            lazy(p<<1|1)=lazy(p<<1)=lazy(p);
            lazy(p)=0; 
        } 
    }
    inline void build(int p,int l,int r)
    {
        l(p)=l,r(p)=r;
        if(l==r) {sum(p)=1;lc(p)=rc(p)=b[pre[l]];return;}
        int mid=l+r>>1;
        build(p<<1,l,mid);
        build(p<<1|1,mid+1,r);
        pushup(p);
    }
    inline void dfs1(int x,int father)
    {
        size[x]=1;
        for(int i=link[x];i;i=a[i].next)
        {
            int y=a[i].y;
            if(y==father) continue;
            fa[y]=x;deep[y]=deep[x]+1;
            dfs1(y,x);    
            size[x]+=size[y];
            if(size[y]>size[wson[x]]) wson[x]=y;
        }
    }
    inline void dfs2(int x,int tp)
    {
        top[x]=tp;
        dfn[x]=++m1;
        pre[m1]=x;
        if(wson[x]) dfs2(wson[x],tp);
        for(int i=link[x];i;i=a[i].next)
        {
            int y=a[i].y;
            if(y==fa[x]||y==wson[x]) continue;
            dfs2(y,y);
        }
    }
    inline void Tree_alter(int p,int l,int r,int k)
    {
        if(l<=l(p)&&r>=r(p))
        {
            sum(p)=1;
            lc(p)=rc(p)=k;
            lazy(p)=k;
            return;
        }
        push(p);
        int mid=l(p)+r(p)>>1;
        if(l<=mid) Tree_alter(p<<1,l,r,k);
        if(r>=mid+1) Tree_alter(p<<1|1,l,r,k);
        pushup(p); 
    }
    inline int Tree_query(int p,int l,int r)
    {
        if(l<=l(p)&&r>=r(p)) return sum(p);
        push(p);
        int ans=0,cnt=0; 
        int mid=l(p)+r(p)>>1;
        if(l<=mid) ans+=Tree_query(p<<1,l,r),cnt++;
        if(r>=mid+1) ans+=Tree_query(p<<1|1,l,r),cnt++;
        if(cnt==2&&rc(p<<1)==lc(p<<1|1)) ans--;
        return ans; 
    }
    inline void alter(int a,int b,int k)
    {
        while(top[a]!=top[b])
        {
            if(deep[top[a]]<deep[top[b]]) swap(a,b);
            Tree_alter(1,dfn[top[a]],dfn[a],k);
            a=fa[top[a]];
        }
        if(deep[a]<deep[b]) swap(a,b);
        Tree_alter(1,dfn[b],dfn[a],k);
    }
    inline int ask(int p,int x)
    {
        if(l(p)==r(p)) return lc(p);
        push(p);
        int mid=l(p)+r(p)>>1;
        if(x<=mid) return ask(p<<1,x);
        else       return ask(p<<1|1,x);
    }
    inline int query(int a,int b)
    {
        int ans=0;
        while(top[a]!=top[b])
        {
            if(deep[top[a]]<deep[top[b]]) swap(a,b);
            ans+=Tree_query(1,dfn[top[a]],dfn[a]);
            if(fa[top[a]]!=0&&ask(1,dfn[top[a]])==ask(1,dfn[fa[top[a]]])) ans--;
            a=fa[top[a]];
         }
         if(deep[a]<deep[b]) swap(a,b);
         ans+=Tree_query(1,dfn[b],dfn[a]);
        return ans; 
    }
    int main()
    {
        n=read();m=read();
        for(int i=1;i<=n;++i) b[i]=read();
        for(int i=1;i<n;++i)
        {
            int x=read(),y=read();
            add(x,y);add(y,x);
        }
        dfs1(1,0);dfs2(1,1);
        build(1,1,n);
        for(int i=1;i<=m;++i)
        {
            char c;cin>>c;
            if(c=='Q') 
            {
                int x=read(),y=read();
                printf("%d
    ",query(x,y));
            }
            else 
            {
                int x=read(),y=read(),k=read();
                alter(x,y,k);
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    ASP.NET 防盗链的实现[HttpHandler]
    html打印表格每页都有的表头和打印分页
    spring是怎样管理mybatis的及注入mybatis mapper bean的
    浅谈Log4j和Log4j2的区别
    git tag — 标签相关操作
    java cocurrent包
    线程实现异步
    使用Shell脚本查找程序对应的进程ID,并杀死进程
    shell脚本监测文件变化
    spring boot的几种配置类型
  • 原文地址:https://www.cnblogs.com/gcfer/p/12128182.html
Copyright © 2020-2023  润新知