【BZOJ-4127】Abs 樹鏈剖分 + 線段樹 (有趣的姿勢)

來源:互聯網
上載者:User

標籤:

4127: AbsTime Limit: 40 Sec  Memory Limit: 256 MB
Submit: 381  Solved: 132
[Submit][Status][Discuss]
Description

給定一棵樹,設計資料結構支援以下操作

1 u   v d  表示將路徑 (u,v) 加d

2 u v 表示詢問路徑 (u,v) 上點權絕對值的和

Input

第一行兩個整數n和m,表示結點個數和運算元

接下來一行n個整數a_i,表示點i的權值

接下來n-1行,每行兩個整數u,v表示存在一條(u,v)的邊

接下來m行,每行一個操作,輸入格式見題目描述 

Output

對於每個詢問輸出答案

Sample Input 4 4
-4 1 5 -2
1 2
2 3
3 4
2 1 3
1 1 4 3
2 1 3
2 3 4
Sample Output 10
13
9
HINT

對於100%的資料,n,m <= 10^5 且 0<= d,|a_i|<= 10^8

SourceSolution

樹鏈剖分顯然,把樹上路徑問題轉化為序列問題

然後線段樹維護區間權值絕對值和,支援區間加

注意Delta>=0這個條件,即1操作保證加數不為負,即實際值不發生減小

於是線段樹維護一些東西:

l,r左右端點;maxf區間最大負數;num區間正數個數-負數個數;tag區間加的標記;sum區間絕對值和

maxf的意義在於,對於區間加Delta,那麼如果maxf+Delta<0很顯然1操作後會出現變號的情況,對於維護絕對值和必然會做出影響,所以用來進行判斷

num的意義在於計算sum的變化,這裡同樣可以考慮維護正數個數和負數個數,但Code起來比較不方便

tag的意義在於,如果區間+Delta不發生變號情況(即maxf+Delta<0||maxf>=0)的時候,可以直接打上標記,否則則需要把標記下放至分葉節點,在向上更新答案

Code
#include<iostream>#include<cstdio>#include<cmath>#include<cstring>#include<algorithm>using namespace std;int read(){    int x=0,f=1; char ch=getchar();    while (ch<‘0‘ || ch>‘9‘) {if (ch==‘-‘) f=-1; ch=getchar();}    while (ch>=‘0‘ && ch<=‘9‘) {x=x*10+ch-‘0‘; ch=getchar();}    return x*f;}#define maxn 110000int n,m,a[maxn];struct Edgenode{int to,next;}edge[maxn<<1];int head[maxn],cnt=1;void add(int u,int v){cnt++; edge[cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt;}void insert(int u,int v){add(u,v); add(v,u);}//----------------------------------------------------------------------------------int size[maxn],fa[maxn],deep[maxn],son[maxn],pl[maxn],sz,pre[maxn],top[maxn],pr[maxn];void dfs_1(int now){    size[now]=1;    for (int i=head[now]; i; i=edge[i].next)        if (edge[i].to!=fa[now])            {                fa[edge[i].to]=now;                deep[edge[i].to]=deep[now]+1;                dfs_1(edge[i].to);                if (size[son[now]]<size[edge[i].to]) son[now]=edge[i].to;                size[now]+=size[edge[i].to];            }}void dfs_2(int now,int chain){    pl[now]=++sz; pre[sz]=a[now]; top[now]=chain;    if (son[now]) dfs_2(son[now],chain);    for (int i=head[now]; i; i=edge[i].next)        if (edge[i].to!=son[now] && edge[i].to!=fa[now])            dfs_2(edge[i].to,edge[i].to);    pr[now]=sz;}//----------------------------------------------------------------------------------struct TreeNode{    int l,r;long long maxf,tag,sum,num;    void Add(int k)         {            if (k<0) maxf=k,sum=-k,num=-1;                else maxf=0,sum=k,num=1;            tag=0;        }}tree[maxn<<2];long long Maxf(long long x,long long y){    if (x>=0 && y>=0) return 0;    if (x>=0 || y>=0) return min(x,y);     return max(x,y);}void Update(int now){    tree[now].maxf=Maxf(tree[now<<1].maxf,tree[now<<1|1].maxf);    tree[now].sum=tree[now<<1].sum+tree[now<<1|1].sum;    tree[now].num=tree[now<<1].num+tree[now<<1|1].num;}void BuildTree(int now,int l,int r){    tree[now].l=l,tree[now].r=r;    if (l==r) {tree[now].Add(pre[l]); return;}    int mid=(l+r)>>1;    BuildTree(now<<1,l,mid); BuildTree(now<<1|1,mid+1,r);    Update(now);}void Pushdown(int now){    if (!tree[now].tag || tree[now].l==tree[now].r) return;    int tag=tree[now].tag; tree[now].tag=0;     tree[now<<1].maxf+=tag; tree[now<<1].sum+=tree[now<<1].num*tag; tree[now<<1].tag+=tag;    tree[now<<1|1].maxf+=tag; tree[now<<1|1].sum+=tree[now<<1|1].num*tag; tree[now<<1|1].tag+=tag;}void Change(int now,int L,int R,int D){    int l=tree[now].l,r=tree[now].r;    if (L<=l && R>=r && (tree[now].maxf>=0 || tree[now].maxf+D<0))         {tree[now].maxf+=D; tree[now].sum+=(long long)tree[now].num*D; tree[now].tag+=D; return;}    if (l==r) {tree[now].Add(tree[now].maxf+D); return;}    Pushdown(now);    int mid=(l+r)>>1;    if (L<=mid) Change(now<<1,L,R,D);    if (R>mid) Change(now<<1|1,L,R,D);    Update(now);}long long Query(int now,int L,int R){        Pushdown(now);    int l=tree[now].l,r=tree[now].r;    if (L<=l && R>=r) return tree[now].sum;        int mid=(l+r)>>1; long long re=0;    if (L<=mid) re+=Query(now<<1,L,R);    if (R>mid) re+=Query(now<<1|1,L,R);    return re;}void DeBug(int now){    int l=tree[now].l,r=tree[now].r;    if (l==r) {printf("l==r=%d   Val=%d  maxf=%lld   tag=%lld   sum=%lld  num=%lld\n",l,a[l],tree[now].maxf,tree[now].tag,tree[now].sum,tree[now].num);return;}    int mid=(l+r)>>1;    DeBug(now<<1); DeBug(now<<1|1); }//----------------------------------------------------------------------------------void Solve_1(int x,int y,int D){    while (top[x]!=top[y])        {            if (deep[top[x]]<deep[top[y]]) swap(x,y);            Change(1,pl[top[x]],pl[x],D);            x=fa[top[x]];        }    if (deep[x]>deep[y]) swap(x,y);    Change(1,pl[x],pl[y],D);}long long Solve_2(int x,int y){    long long re=0;    while (top[x]!=top[y])        {            if (deep[top[x]]<deep[top[y]]) swap(x,y);            re+=Query(1,pl[top[x]],pl[x]);            x=fa[top[x]];         }    if (deep[x]>deep[y]) swap(x,y);    re+=Query(1,pl[x],pl[y]);    return re;}//----------------------------------------------------------------------------------int main(){//    freopen("4127.in","r",stdin);//    freopen("4127.out","w",stdout);    n=read(),m=read();    for (int i=1; i<=n; i++) a[i]=read();    for (int u,v,i=1; i<=n-1; i++) u=read(),v=read(),insert(u,v);    dfs_1(1); dfs_2(1,1); BuildTree(1,1,n);    int opt,u,v,w;    while (m--)        {            opt=read();        //    DeBug(1);             if (opt==1) u=read(),v=read(),w=read(),Solve_1(u,v,w);            else u=read(),v=read(),printf("%lld\n",Solve_2(u,v));        }    return 0;}

這道破題,兩天前YveH和Etienne寫了半天多,DCrusher大爺嘲諷他們,我替他們不服,然後自己果斷寫了1小時,然後調了3小時....發現自信寫不錯的鏈剖少打了一句話MDZZ

(加上省隊集訓,第三題暴力打到70%就去吃飯了,回來懶得打了,體驗了連續滾粗的快感)

發現自己的常數已經接近Etienne了...就慢個100ms不到

 

【BZOJ-4127】Abs 樹鏈剖分 + 線段樹 (有趣的姿勢)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.