Problem B. Money out of Thin Air
算法:
1.先用DFS把员工之间关系系列找出,使之连续,转换为对线段进行操作,用L【】记录左边界,R【】记录右边界。
2.线段树,单点更新,区间更新,lazy延时标记。
View Code
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<iostream> #include<vector> using namespace std; #define MAXN 51000 #define LL long long struct node { int left, right; LL salary; LL lazy; }seg[500010]; int N, M; int salary[MAXN], visit[MAXN]; int L[MAXN], R[MAXN], dfn[MAXN]; int que[MAXN]; vector<int>p[51100]; void build(int l, int r, int root) { int mid = (l + r) / 2; seg[root].left = l; seg[root].right = r; seg[root].lazy = 0; if( l == r ) { seg[root].salary = salary[dfn[l]]; return; } build(l,mid,root*2); build(mid+1,r,root*2+1); seg[root].salary = seg[root*2].salary + seg[root * 2 + 1].salary; } void update(int x) { seg[x * 2].lazy += seg[x].lazy; seg[x * 2].salary += (LL) (seg[x * 2].right - seg[x * 2].left + 1 ) * seg[x].lazy; seg[x * 2 + 1].lazy += seg[x].lazy; seg[x * 2 + 1].salary += (LL) (seg[x * 2 + 1].right - seg[x * 2 + 1].left + 1 ) * seg[x].lazy; seg[x].lazy = 0; } void add( int root, int u, int v, int val) { int mid = (seg[root].left + seg[root].right) / 2; if( seg[root].left == u && v == seg[root].right ) { seg[root].lazy += val; seg[root].salary += (LL) (v - u + 1) * val; return; } if( seg[root].lazy != 0 ) update( root ); if( u > mid ) add( root * 2 + 1, u, v, val); else if( v <= mid ) add( root * 2, u, v, val); else { add( root * 2, u, mid, val); add( root * 2 + 1, mid + 1, v,val); } seg[root].salary = seg[root*2].salary + seg[root * 2 + 1].salary; } LL sum( int root,int u, int v) { int mid = (seg[root].left + seg[root].right) / 2; if( seg[root].left == u && v == seg[root].right ) { return seg[root].salary; } if( seg[root].lazy != 0 ) update(root); LL st = 0; if( u > mid ) return sum( root * 2 + 1, u, v); else if( v <= mid ) st += sum( root * 2, u, v); else { st += sum( root * 2, u, mid); st += sum( root * 2 + 1, mid + 1, v); } return st; } int main( ) { int pid, x, f, id, a, b, c, fuck = 0; char str[100]; while( scanf("%d%d%d",&N,&M,&salary[0]), N|M|salary[0]) { for( int i = 0; i <= N; i++) p[i].clear(); for( int i = 1; i < N; i++) { scanf("%d%d",&a,&salary[i]); p[a].push_back(i); } memset(visit,0,sizeof(visit)); memset(L, 0, sizeof(L)); memset(R, 0, sizeof(R)); pid = 0; id = 0; que[pid] = 0; dfn[id] = 0; while( pid >= 0 ) { int u = que[pid]; if( !visit[u] ) { dfn[id] = u; L[u] = id; visit[u] = 1; id++; } int n = p[u].size(); f = 0; for( x = 0; x < n; x++) { if( !visit[p[u][x]] ) { que[++pid] = p[u][x]; //进栈 f = 1; //break; 没去掉这个一直TLE,速度太慢,一次入栈就可以了 } } if( f ) continue; if( x == n ) { R[u] = id - 1; --pid; //退栈 } } build(0,N-1,1); for( int i = 1; i <= M; i++) { scanf("%s%d%d%d",str,&a,&b,&c); if( str[0] == 'e' ) { LL x = sum(1,L[a],L[a]); if( x < b ) add(1,L[a],L[a],c); } else { LL x = sum(1,L[a],R[a]); if( x < (LL) (R[a] - L[a] + 1 ) * b ) add(1, L[a],R[a],c); } } if( fuck ) puts(""); fuck = 1; for( int i = 0; i < N; i++) { printf("%lld\n",sum(1,L[i],L[i])); } } return 0; }
posted on 2012-07-25 07:41 more think, more gains 阅读(172) 评论(0) 编辑 收藏 举报