1. 程式人生 > >【BZOJ3730】震波(動態點分治)[複習]

【BZOJ3730】震波(動態點分治)[複習]

題面

BZOJ

題解

動態點分治什麼的完全不記得了。這回重新寫一寫。
首先我們把點分樹給建出來。
操作只有兩種,修改和詢問距離某個點的距離不超過\(k\)的點的和。
兩點之間的距離可以樹鏈剖分之類的算,這裡不再重複。
考慮如何計算答案。
對於每個點,把對於它的點分樹上所有祖先的貢獻給加好。
因為要方便區間求和,所以利用動態開點線段樹實現。
假設當前點距離點分樹上某祖先的距離為\(dis\),那麼就把這個祖先的線段樹的\(dis\)位置加上當前點的權值。
每次詢問的時候只需要沿著點分樹的父親走,然後每次詢問線段樹上\([0,k-dis(fa,u)]\)的和就好了。
但是這樣有個問題,對於當前點的子樹,它的貢獻會在所有點分樹上的祖先位置被重複計算。
所以我們再額外維護一棵線段樹,表示當前點的所有子樹中,對於它點分樹父親的貢獻,
這樣子每次把重複算的給減去就好了。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 111111
inline int read()
{
    RG int x=0,t=1;RG char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
int n,m,V[MAX];
struct Line{int v,next;}e[MAX<<1];
int h[MAX],cnt=1;
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
/********************************************************************/
int size[MAX],dfn[MAX],top[MAX],dep[MAX],fa[MAX],tim,hson[MAX];
void dfs1(int u,int ff)
{
    fa[u]=ff;size[u]=1;dep[u]=dep[ff]+1;
    for(int i=h[u];i;i=e[i].next)
    {
        int v=e[i].v;if(v==ff)continue;
        dfs1(v,u);size[u]+=size[v];
        if(size[v]>size[hson[u]])hson[u]=v;
    }
}
void dfs2(int u,int tp)
{
    top[u]=tp;
    if(hson[u])dfs2(hson[u],tp);
    for(int i=h[u];i;i=e[i].next)
        if(e[i].v!=fa[u]&&e[i].v!=hson[u])
            dfs2(e[i].v,e[i].v);
}
int LCA(int u,int v)
{
    while(top[u]^top[v])dep[top[u]]<dep[top[v]]?v=fa[top[v]]:u=fa[top[u]];
    return dep[u]<dep[v]?u:v;
}
int Dis(int u,int v){return dep[u]+dep[v]-2*dep[LCA(u,v)];}
/********************************************************************/
bool vis[MAX];
int Fa[MAX],Size,root,mx;
void Getroot(int u,int ff)
{
    size[u]=1;int ret=0;
    for(int i=h[u];i;i=e[i].next)
    {
        int v=e[i].v;if(v==ff||vis[v])continue;
        Getroot(v,u);size[u]+=size[v];
        ret=max(ret,size[v]);
    }
    ret=max(ret,Size-size[u]);
    if(ret<mx)mx=ret,root=u;
}
void DFS(int u,int ff)
{
    vis[u]=true;Fa[u]=ff;
    for(int i=h[u];i;i=e[i].next)
    {
        int v=e[i].v;if(vis[v])continue;
        mx=Size=size[v];
        Getroot(v,u);DFS(root,u);
    }
}
/********************************************************************/
int rt[MAX<<1],tot;
struct Node{int ls,rs,v;}t[MAX<<6];
void Modify(int &x,int l,int r,int p,int w)
{
    if(!x)x=++tot;t[x].v+=w;if(l==r)return;
    int mid=(l+r)>>1;
    if(p<=mid)Modify(t[x].ls,l,mid,p,w);
    else Modify(t[x].rs,mid+1,r,p,w);
}
int Query(int x,int l,int r,int L,int R)
{
    if(!x)return 0;if(L<=l&&r<=R)return t[x].v;
    int mid=(l+r)>>1,ret=0;
    if(L<=mid)ret+=Query(t[x].ls,l,mid,L,R);
    if(R>mid)ret+=Query(t[x].rs,mid+1,r,L,R);
    return ret;
}
/********************************************************************/
void Modify(int x,int w)
{
    Modify(rt[x],0,n,0,w);
    for(int i=x;Fa[i];i=Fa[i])
    {
        int dis=Dis(x,Fa[i]);
        Modify(rt[Fa[i]],0,n,dis,w);
        Modify(rt[i+n],0,n,dis,w);
    }
}
int Query(int x,int K)
{
    int ret=Query(rt[x],0,n,0,K);
    for(int i=x;Fa[i];i=Fa[i])
    {
        int dis=Dis(x,Fa[i]);if(dis>K)continue;
        ret+=Query(rt[Fa[i]],0,n,0,K-dis);
        ret-=Query(rt[i+n],0,n,0,K-dis);
    }
    return ret;
}
/********************************************************************/
int main()
{
    n=read();m=read();
    for(int i=1;i<=n;++i)V[i]=read();
    for(int i=1;i<n;++i)
    {
        int u=read(),v=read();
        Add(u,v);Add(v,u);
    }
    dfs1(1,0);dfs2(1,1);
    Size=mx=n;Getroot(1,0);DFS(root,0);
    for(int i=1;i<=n;++i)Modify(i,V[i]);
    int ans=0;
    while(m--)
    {
        int opt=read(),x=read()^ans,y=read()^ans;
        if(opt==0)printf("%d\n",ans=Query(x,y));
        else Modify(x,y-V[x]),V[x]=y;
    }
    return 0;
}

相關推薦

BZOJ3730震波動態分治[複習]

題面 BZOJ 題解 動態點分治什麼的完全不記得了。這回重新寫一寫。 首先我們把點分樹給建出來。 操作只有兩種,修改和詢問距離某個點的距離不超過\(k\)的點的和。 兩點之間的距離可以樹鏈剖分之類的算,這裡不再重複。 考慮如何計算答案。 對於每個點,把對於它的點分樹上所有祖先的貢獻給加好。 因為要方便區間求和

BZOJ3730震波動態分治

www pre size getch post str http clu cto 【BZOJ3730】震波(動態點分治) 題面 BZOJ 題意 給定一棵樹, 每次詢問到一個點的距離\(<=K\)的點的權值之和 動態修改權值, 強制在線 題解 正常的\(DP\)???

BZOJ3730震波動態分治[復習]

problem 超過 printf mes 區間 odi ++ iostream int 題面 BZOJ 題解 動態點分治什麽的完全不記得了。這回重新寫一寫。 首先我們把點分樹給建出來。 操作只有兩種,修改和詢問距離某個點的距離不超過\(k\)的點的和。 兩點之間的距離可以

BZOJ3924幻想鄉戰略遊戲動態分治

truct 產生 。。 sum 遊戲 stream str pos struct 【BZOJ3924】幻想鄉戰略遊戲(動態點分治) 題面 權限題。。。(窮死我了) 洛谷 題解 考慮不修改 發現一個貪心的做法 假設當前放在當前位置 如果它有一個子樹的兵的總數大於總數的一半 那

Luogu3676小清新數據結構題動態分治

證明 路徑 ont getchar ostream fin org 線段 fine 【Luogu3676】小清新數據結構題(動態點分治) 題面 洛谷 題解 先扯遠點,這題我第一次看的時候覺得是一個樹鏈剖分+線段樹維護。 做法大概是這樣: 我們先以任意一個點為根,把當前點看成

nowcoder 4th T1 動態分治

lld 技術分享 bits info urn img check std 就會 題目鏈接:https://www.nowcoder.com/acm/contest/175/A 題目名字嚇死人 std: 我 太可啪了 一道簡單的模擬題。雖然我把題意想錯了。 按照題意模擬輸

BZOJ4012 [HNOI2015]開店 動態分治

moto 沒有 多少 flag ack 一個點 operator 連接 iostream Description 風見幽香有一個好朋友叫八雲紫,她們經常一起看星星看月亮從詩詞歌賦談到 人生哲學。最近她們靈機一動,打算在幻想鄉開一家小店來做生意賺點錢。這樣的 想法

ZJOI 2015 幻想鄉戰略遊戲動態分治

題意 https://loj.ac/problem/2135 思路 首先要明確一點,答案分佈是有單調性的。什麼意思呢?假設我們的答案在 \(u\) 節點,\((u,v)\) 之間有一條邊且 \(u\) 離答案所在的點更近,那麼 \(u\) 節點作為答案一定不比在 \(v\) 節點作答案劣。從鏈的角度分析

bzoj3924 [Zjoi2015]幻想鄉戰略遊戲動態分治

就是求帶權重心,可以修改點權。 我們首先建出重心樹。對於每個節點x記 s1[x]–x的子樹到x的答案, s2[x]–x的子樹的點權和, s3[x]–x的子樹到fa[x]的答案。 那我們就可以通過這些資訊得出以x為重心的答案(在重心樹上一直往上跳,複雜度

bzoj5192 [Usaco2018 Feb]New Barns動態分治

考試時傻掉了qaq,雖然是不斷加點,但是沒有強制線上,我們可以離線做,把樹的形態先搞出來,然後對最終的樹形態直接點分治,建出重心樹,然後考慮每次的加點操作為啟用這個點即可。 考慮我們如何找到距x最遠的啟用點,假設當前根為c。則答案就是x距c的距離再加上c的不含

[BZOJ3924][Zjoi2015]幻想鄉戰略遊戲動態分治

看到資料範圍和6s的時限,得(cai)出是一道動態點分治。 這道題有一個巧妙的思路: 假設當前補給站為uu,並強制以uu為根,vv為uu的一個子節點,sumdusumdu和sumdvsumdv分別為uu的子樹內的dd之和以及vv的子樹內的dd之和,len(u

BZOJ3730震波 - 動態分治

code inpu 通過 next sin 其中 分治 n-1 print 題意: Description 在一片土地上有N個城市,通過N-1條無向邊互相連接,形成一棵樹的結構,相鄰兩個城市的距離為1,其中第i個城市的價值為value[i]。 不幸的是,這片土地常常發

WC2018即時戰略動態分治,替罪羊樹

思想 聽說 否則 ++i ostream sin date names shuff 【WC2018】即時戰略(動態點分治,替罪羊樹) 題面 UOJ 題解 其實這題我也不知道應該怎麽確定他到底用了啥。只是想法很類似就寫上了QwQ。 首先鏈的部分都告訴你要特殊處理那就沒有辦法只

BZOJ1316樹上的詢問 分治+set

find hint name 維護 tdi log string cnblogs 每次 【BZOJ1316】樹上的詢問 Description 一棵n個點的帶權有根樹,有p個詢問,每次詢問樹中是否存在一條長度為Len的路徑,如果是,輸出Yes否輸出No. Input

BZOJ1899午餐動態規劃

需要 記錄 表示 列隊 其中 truct ble read namespace 【BZOJ1899】午餐(動態規劃) 題面 BZOJ 題解 我太弱了 這種\(dp\)完全做不動。。 首先,感性理解一些 如果所有人都要早點走, 那麽,吃飯時間長的就先吃 吃飯時間短的就晚點吃

BZOJ4455小星星動態規劃,容斥

之間 lld algorithm std 還需要 tchar 一次 lin 還需 【BZOJ4455】小星星(動態規劃,容斥) 題面 BZOJ 洛谷 Uoj 題解 題意說簡單點就是給定一張\(n\)個點的圖和一棵\(n\)個點的樹,現在要讓圖和樹之間的點一一對應,並且如果樹

HDU4689Derangement動態規劃

tdi 位置 while 表示 ++ fine cstring pri com 【HDU4689】Derangement(動態規劃) 題面 Vjudge 給定一個\(+-\)組成的字符串,長度為\(n\)。 如果第\(i\)位是\(+\),那麽\(p_i>i\),否則

MATLAB eps 相對精度簡介

目錄   eps Syntax Description Accuracy in Double Precision Accuracy in Single Precision eps Floating-point relative accuracy

BZOJ4712洪水動態dp

【BZOJ4712】洪水(動態dp) 題面 BZOJ 然而是許可權題QwQ,所以粘過來算了。 Description 小A走到一個山腳下,準備給自己造一個小屋。這時候,小A的朋友(op,又叫管理員)打開了創造模式,然後飛到 山頂放了格水。於是小A面前出現了一個瀑布。作為平民的小A只好老實巴交地爬山堵水

HDU 4918 Query on the subtree動態分治+樹狀陣列

題意 給定一棵 \(n\) 個節點的樹,每個節點有點權。完成 \(q\) 個操作——操作分兩種:修改點 \(x\) 的點權、查詢與 \(x\) 距離小於等於 \(d\) 的權值總和。 \(1 \leq n,q \leq 10^5\) 思路 從最簡單的情況分析——只有一次查詢。當然一遍 \(O(n)\)