給你一棵包含N個節點的樹,設每條邊一開始的邊權爲0,如今有兩種操做:
1)給出參數U,V,C,表示把U與V之間的路徑上的邊權變成C(保證C≥0)
2)給出參數U,V,C,表示把U與V之間的路徑上的邊權加上C。可是若是U至V之間路徑某條邊的邊權加上C小於0,那麼C=這條邊的邊權的相反數。
你須要統計出每次一操做事後樹中邊權爲0的邊有多少條。
就是兩個操做:1.樹鏈覆蓋C 2.樹鏈+C,若是有邊+C<0 則C=-minxphp
隨便鏈剖一下+線段樹維護一下就能夠了ios
維護最小值minx,最小值個數minnui
覆蓋的時候直接覆蓋,+C的時候先查詢minx再看看是否修改C,而後+C...輸出答案就是,若是minx=0,ans+=minn....spa
邊權的樹鏈剖分,就是把邊權下放至點權code
邊<u,v>的值,由u,v中較深的點保存,這樣顯然除了root每條邊和每一個點是一一對應的.blog
這裏查詢全部邊的值,由於默認1爲root,因此直接查詢[2,N]的就能夠了。修改的時候稍微作一下修改就能夠了ip
因此說隨便寫寫就A了.get
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> using namespace std; inline 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=10*x+ch-'0'; ch=getchar();} return x*f; } #define MAXN 100010 struct EdgeNode{int next,to;}edge[MAXN<<1]; int head[MAXN],cnt=1; void AddEdge(int u,int v) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v;} void InsertEdge(int u,int v) {AddEdge(u,v); AddEdge(v,u);} int N,M; #define INF 0x7fffffff namespace SegmentTree { struct SegmentTreeNode{int l,r,size,minx,minn,tag,del;}tree[MAXN<<2]; #define ls now<<1 #define rs now<<1|1 inline void Update(int now) { tree[now].minx=min(tree[ls].minx,tree[rs].minx); tree[now].minn=tree[ls].minx<tree[rs].minx? tree[ls].minn:tree[rs].minn; if (tree[ls].minx==tree[rs].minx) tree[now].minx=tree[ls].minx,tree[now].minn=tree[ls].minn+tree[rs].minn; } inline void PushDown(int now) { if (tree[now].del!=-1) { tree[ls].minx=tree[now].del; tree[ls].minn=tree[ls].size; tree[ls].del=tree[now].del; tree[ls].tag=0; tree[rs].minx=tree[now].del; tree[rs].minn=tree[rs].size; tree[rs].del=tree[now].del; tree[rs].tag=0; tree[now].del=-1; } if (tree[now].tag) { tree[ls].minx+=tree[now].tag; tree[ls].tag+=tree[now].tag; tree[rs].minx+=tree[now].tag; tree[rs].tag+=tree[now].tag; tree[now].tag=0; } } inline void BuildTree(int now,int l,int r) { tree[now].l=l,tree[now].r=r,tree[now].size=r-l+1; tree[now].del=-1; tree[now].tag=0; if (l==r) {tree[now].minn=1; tree[now].minx=0; return;} int mid=(l+r)>>1; BuildTree(ls,l,mid); BuildTree(rs,mid+1,r); Update(now); } inline void Change(int now,int L,int R,int C) { int l=tree[now].l,r=tree[now].r; if (L<=l && R>=r) {tree[now].tag+=C; tree[now].minx+=C; return;} PushDown(now); int mid=(l+r)>>1; if (L<=mid) Change(ls,L,R,C); if (R>mid) Change(rs,L,R,C); Update(now); } inline void Modify(int now,int L,int R,int C) { int l=tree[now].l,r=tree[now].r; if (L<=l && R>=r) {tree[now].del=C; tree[now].tag=0; tree[now].minx=C; tree[now].minn=tree[now].size; return;} PushDown(now); int mid=(l+r)>>1; if (L<=mid) Modify(ls,L,R,C); if (R>mid) Modify(rs,L,R,C); Update(now); } inline int Getmin(int now,int L,int R) { int l=tree[now].l,r=tree[now].r; if (L<=l && R>=r) return tree[now].minx; PushDown(now); int mid=(l+r)>>1,re=INF; if (L<=mid) re=min(re,Getmin(ls,L,R)); if (R>mid) re=min(re,Getmin(rs,L,R)); return re; } inline int Query(int now,int L,int R) { int l=tree[now].l,r=tree[now].r; if (L<=l && R>=r) return tree[now].minx==0? tree[now].minn:0; PushDown(now); int mid=(l+r)>>1,re=0; if (L<=mid) re+=Query(ls,L,R); if (R>mid) re+=Query(rs,L,R); return re; } } namespace ChainPartition { int size[MAXN],fa[MAXN],deep[MAXN],top[MAXN],pl[MAXN],pr[MAXN],pre[MAXN],dfn,son[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]) { deep[edge[i].to]=deep[now]+1; fa[edge[i].to]=now; DFS_1(edge[i].to); size[now]+=size[edge[i].to]; if (size[son[now]]<size[edge[i].to]) son[now]=edge[i].to; } } void DFS_2(int now,int chain) { top[now]=chain; pl[now]=++dfn; pre[dfn]=now; if (son[now]) DFS_2(son[now],chain); for (int i=head[now]; i; i=edge[i].next) if (edge[i].to!=fa[now] && edge[i].to!=son[now]) DFS_2(edge[i].to,edge[i].to); pr[now]=dfn; } inline int Get(int x,int y) { int re=INF; while (top[x]!=top[y]) { if (deep[top[x]]<deep[top[y]]) swap(x,y); re=min(re,SegmentTree::Getmin(1,pl[top[x]],pl[x])); x=fa[top[x]]; } if (deep[x]>deep[y]) swap(x,y); if (x!=y) re=min(re,SegmentTree::Getmin(1,pl[x]+1,pl[y])); return re; } inline void Change(int x,int y,int C) { int minx=Get(x,y); if (minx+C<0) C=-minx; // printf("Change %d %d %d\n",x,y,C); while (top[x]!=top[y]) { if (deep[top[x]]<deep[top[y]]) swap(x,y); SegmentTree::Change(1,pl[top[x]],pl[x],C); x=fa[top[x]]; } if (deep[x]>deep[y]) swap(x,y); if (x!=y) SegmentTree::Change(1,pl[x]+1,pl[y],C); printf("%d\n",SegmentTree::Query(1,2,N)); } inline void Modify(int x,int y,int C) { // printf("Modify %d %d %d\n",x,y,C); while (top[x]!=top[y]) { if (deep[top[x]]<deep[top[y]]) swap(x,y); SegmentTree::Modify(1,pl[top[x]],pl[x],C); x=fa[top[x]]; } if (deep[x]>deep[y]) swap(x,y); if (x!=y) SegmentTree::Modify(1,pl[x]+1,pl[y],C); printf("%d\n",SegmentTree::Query(1,2,N)); } } int main() { N=read(),M=read(); for (int x,y,i=1; i<=N-1; i++) x=read(),y=read(),InsertEdge(x,y); ChainPartition::DFS_1(1); ChainPartition::DFS_2(1,1); SegmentTree::BuildTree(1,1,N); while (M--) { int opt=read(),u=read(),v=read(),C=read(); switch (opt) { case 1: ChainPartition::Modify(u,v,C); break; case 2: ChainPartition::Change(u,v,C); break; } } return 0; }
之前看蛋蛋寫了好幾天....還找Claris要代碼.....string
1h左右就A了....不過無端弄了個本題第一個REit
ShallWe:"這不是傻逼題麼?"