1. 程式人生 > >BZOJ4127 Abs (樹鏈剖分 線段樹)

BZOJ4127 Abs (樹鏈剖分 線段樹)

題目大意

給出一棵帶權有根樹,要求完成以下幾種操作:

1 u v d 表示將路徑 (u,v) 加d (0<=d<=1e8)
2 u v 表示詢問路徑 (u,v) 上點權絕對值的和

題解

正常樹剖,用線段樹維護幾個資訊:絕對值的和區間內負數的個數區間內最大的負數 以及 最大的負數所在的位置,因為有區間加操作,所以還要維護一個加標記

這道題棘手的地方就在於,數字的正負性會隨著區間加操作而改變,所以說不能直接維護區間和。所以說觀察資料範圍 (0<=d<=1e8) 可以得知這道題序列中的所有數字,只會從負變正而不會從正變負,所以說序列內數字的正負性最多隻改變n次

,所以對於每次數字正負性的變化暴力修改就可以了。

每次處理一個區間加操作之前,先檢查區間內進行這個加操作之後是否會有數字的正負性發生改變,也就是說區間內最大的負數改變之後是否大於等於0。如果有的話遞迴改變那個位置元素的正負性更新線段數,然後再進行加操作。

其他操作與普通樹剖線段數無異,祝大家1A。

程式碼

#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;

const int maxx=40000008
; char Input[maxx+5],*ipos; #define read() (strtol(ipos,&ipos,10)) const int maxn=int(1e5)+11, inf=1<<30; int n,m,v[maxn]; int tot=0,head[maxn]; struct Edge { int from,to,next; Edge() {} Edge(int x,int y,int nx):from(x),to(y),next(nx) {} }eage[maxn*2]; inline void add(int x,int y) { eage[tot]=Edge(x,y,head[x]), head[x]=tot++; eage[tot]=Edge(y,x,head[y]), head[y]=tot++; return
; } int fa[maxn],dep[maxn],siz[maxn],son[maxn]; inline void dfs1(register int u) { siz[u]=1, son[u]=0; for(register int i=head[u];~i;i=eage[i].next) if(eage[i].to!=fa[u]) { fa[eage[i].to]=u; dep[eage[i].to]=dep[u]+1; dfs1(eage[i].to); siz[u]+=siz[eage[i].to]; if(siz[eage[i].to]>siz[son[u]]) son[u]=eage[i].to; } } int top[maxn],seq[maxn],id[maxn],ind; int val[maxn]; inline void dfs2(register int u) { seq[++ind]=u, id[u]=ind; if(son[fa[u]]==u) top[u]=top[fa[u]]; else top[u]=u; if(son[u]) dfs2(son[u]); register int i; for(i=head[u];~i;i=eage[i].next) if(eage[i].to!=fa[u] && eage[i].to!=son[u]) dfs2(eage[i].to); } #define mp make_pair #define ls(k) ((k)<<1) #define rs(k) (ls(k)^1) #define mid ((l+r)>>1) struct Node { long long sum,add; int len,cnt; pair<int,int> pos; inline void get_add(long long); inline void maintain(const Node&,const Node&); }node[maxn*4]; inline void Node:: get_add(long long a) { sum+=(len-2*cnt)*a, add+=a; if(pos.first!=-inf) pos.first+=a; return; } inline void pushdown(int k) { Node &ls=node[ls(k)], &rs=node[rs(k)]; long long &add=node[k].add; if(add) { ls.get_add(add), rs.get_add(add); add=0; } return; } inline void Node:: maintain(const Node &a,const Node &b) { sum=a.sum+b.sum; add=0; len=a.len+b.len; cnt=a.cnt+b.cnt; pos=max(a.pos,b.pos); } inline void build(int k,int l,int r) { node[k].len=r-l+1; if(l==r) { node[k].sum=(int)abs(1.0*val[l]); if(val[l]>=0) node[k].pos=mp(-inf,0); else node[k].cnt=1, node[k].pos=mp(val[l],l); return; } build(ls(k),l,mid); build(rs(k),mid+1,r); node[k].maintain(node[ls(k)],node[rs(k)]); return; } void Build() { build(1,1,n); return; } inline void modify(int k,int l,int r,int ql,int qr,int val) { if(l!=r) pushdown(k); if(ql<=l && r<=qr) { node[k].get_add(val); return; } if(ql<=mid) modify(ls(k),l,mid,ql,qr,val); if(qr> mid) modify(rs(k),mid+1,r,ql,qr,val); node[k].maintain(node[ls(k)],node[rs(k)]); return; } void modify(int l,int r,int a) { modify(1,1,n,l,r,a); return; } inline void flip(int k,int l,int r,int pos) { if(l!=r) pushdown(k); if(l==r) { node[k].sum*=-1; node[k].cnt=0; node[k].pos=mp(-inf,0); return; } if(pos<=mid) flip(ls(k),l,mid,pos); if(pos> mid) flip(rs(k),mid+1,r,pos); node[k].maintain(node[ls(k)],node[rs(k)]); return; } void flip(int pos) { flip(1,1,n,pos); return; } inline pair<int,int> get_pos(int k,int l,int r,int ql,int qr) { if(l!=r) pushdown(k); if(ql<=l && r<=qr) return node[k].pos; pair<int,int> res=mp(-inf,0); if(ql<=mid) res=max(res,get_pos(ls(k),l,mid,ql,qr)); if(qr> mid) res=max(res,get_pos(rs(k),mid+1,r,ql,qr)); return res; } pair<int,int> get_pos(int l,int r) { return get_pos(1,1,n,l,r); } inline long long query(int k,int l,int r,int ql,int qr) { if(l!=r) pushdown(k); if(ql<=l && r<=qr) return node[k].sum; long long res=0; if(ql<=mid) res+=query(ls(k),l,mid,ql,qr); if(qr> mid) res+=query(rs(k),mid+1,r,ql,qr); return res; } long long Query(int l,int r) { return query(1,1,n,l,r); } inline void Modify(int l,int r,int val) { while(true) { pair<int,int> pos=get_pos(l,r); if(pos.first+val>=0) flip(pos.second); else break; } modify(l,r,val); return; } inline void Tree_modify(register int u,register int v,int a) { while(top[u]!=top[v]) { if(dep[top[u]]<dep[top[v]]) std::swap(u,v); Modify(id[top[u]],id[u],a); u=fa[top[u]]; } if(dep[u]>dep[v]) std::swap(u,v); Modify(id[u],id[v],a); return; } inline long long Tree_query(int u,int v) { long long res=0; while(top[u]!=top[v]) { if(dep[top[u]]<dep[top[v]]) std::swap(u,v); res+=Query(id[top[u]],id[u]); u=fa[top[u]]; } if(dep[u]>dep[v]) std::swap(u,v); res+=Query(id[u],id[v]); return res; } int main() { #ifndef ONLINE_JUDGE freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); #endif // ONLINE_JUDGE fread(Input,maxx,1,stdin);ipos=Input; n=read(), m=read(); for(int i=1;i<=n;i++) { head[i]=-1; v[i]=read(); } for(int x,y,i=1;i<n;i++) { x=read(), y=read(); add(x,y); } dep[1]=1, fa[1]=-1; dfs1(1), dfs2(1); for(int i=1;i<=n;i++) val[i]=v[seq[i]]; Build(); int op,u,v,a; for(int i=1;i<=m;i++) { op=read(), u=read(), v=read(); if(op==1) { a=read(); Tree_modify(u,v,a); } else { printf("%lld\n",Tree_query(u,v)); } } return 0; }

資料生成器:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <ctime>
using namespace std;

const int n=int(1e5), m=n;
int maxdep=0;
bool vis[n+11];
int f[n+11];

inline int _find(register int k) {
    if(f[k]==k) return k;
    return f[k]=_find(f[k]);
}

int main() {
    freopen("input0.txt","w",stdout);
    srand(time(NULL));

    printf("%d %d\n",n,m);
    for(int i=1;i<=n;i++) {
        int sign=rand()&1;
        sign=sign?1:-1;
        printf("%d ",sign*rand());
    }
    printf("\n");

    for(int i=1;i<=n;i++)
        f[i]=i;
    int tot=0;
    while(tot<n-1) {
        int u=(1ll*rand()*rand())%n+1, v=(1ll*rand()*rand())%n+1;
        int g1=_find(u), g2=_find(v);
        if(g1!=g2) {
            f[g1]=g2;
            printf("%d %d\n",u,v);
            tot++;
        }
    }

    for(int i=1;i<=m;i++) {
        int op=rand()%2+1;
        int u=(1ll*rand()*rand())%n+1, v=(1ll*rand()*rand())%n+1, d=(1ll*rand()*rand())%((int)1e5)+1;
        if(op==1) printf("%d %d %d %d\n",op,u,v,d);
        else printf("%d %d %d\n",op,u,v);
    }

    return 0;
}