2016"百度之星" - 初赛(Astar Round2A)
http://acm.hdu.edu.cn/showproblem.php?pid=5692
题意:给一棵树,点有权值. 操作1:询问从0点出发,经过x点(输入)的路径中,点权和最大的路径的和是多少. 操作2:将x号点的值更新为y.
思路:已0为根形成一个有根树,经过x点的所有路径的终点都在已x为根的子树中,问题相当于求一颗子树中的所有节点到0点的距离最大值,将题目的点权理解成距离.
解法:用dfs顺序对0为根的树标号,按照标号作为线段树的序号,那么某一颗子树的点在线段树的区间也是连续的了,这是一个常见的做法,参见线段树专题的树标号.
然后bfs,dfs都可以,处理出初始每个点作为终点到0点的路径和. 简单的累加. 线段树维护的是以0为起点 x为终点的路径和数组.
对于查询操作,就是线段树最大值查询. 对于更新操作, 变化量 delta= now - pre , 如果一个点值变大delta ,那么以该点为根的子树, 每个点的路径和都会增加这么多,线段树区间更新 +delta.
1 //#define debug 2 #include<cstdio> 3 #include<cstdlib> 4 #include<vector> 5 #define lrrt int L,int R,int rt 6 #define iall 1,n,1 7 #define imid int mid=(L+R)>>1 8 #define lson L,mid,rt<<1 9 #define rson mid+1,R,rt<<1|1 10 using namespace std; 11 typedef long long LL; 12 const LL inf=0x3f3f3f3f3f3f3f3fLL; 13 const int M=1e5+10; 14 int n,m; 15 struct E{ 16 int u,v; 17 }e[M]; 18 struct Q{ 19 int type,x; 20 LL y; 21 }q[M]; 22 int a[M]; 23 vector<LL> answer; 24 vector<int> g[M]; 25 struct N{ 26 int l,r; 27 }node[M]; 28 LL dist[M]; 29 int Index; 30 struct T{ 31 LL value,lazy; 32 }tree[M<<2]; 33 void init(){ 34 for(int i=0;i<n;i++){ 35 g[i].clear(); 36 } 37 for(int i=0;i<n-1;i++){ 38 int u=e[i].u; 39 int v=e[i].v; 40 g[u].push_back(v); 41 g[v].push_back(u); 42 } 43 } 44 void dfs(int u,int fa){ 45 node[u].l=++Index; 46 for(int i=0;i<g[u].size();i++){ 47 int v=g[u][i]; 48 if(v==fa) continue; 49 dfs(v,u); 50 } 51 node[u].r=Index; 52 } 53 void dfs_for_dist(int u,int fa){ 54 for(int i=0;i<g[u].size();i++){ 55 int v=g[u][i]; 56 if(v==fa) continue; 57 dist[v]+=dist[u]; 58 dfs_for_dist(v,u); 59 } 60 } 61 void build(lrrt){ 62 tree[rt].value=0; 63 tree[rt].lazy=0; 64 if(L==R) return ; 65 imid; 66 build(lson); 67 build(rson); 68 } 69 void pushup(int rt){ 70 tree[rt].value=max(tree[rt<<1].value,tree[rt<<1|1].value); 71 } 72 void pushdown(int rt){ 73 LL &z=tree[rt].lazy; 74 if(z!=0){ 75 tree[rt<<1].lazy+=z; 76 tree[rt<<1|1].lazy+=z; 77 tree[rt<<1].value+=z; 78 tree[rt<<1|1].value+=z; 79 z=0; 80 } 81 } 82 void update(int x,int y,LL z,lrrt){ 83 if(x<=L&&R<=y){ 84 tree[rt].value+=z; 85 tree[rt].lazy+=z; 86 return ; 87 } 88 imid; 89 pushdown(rt); 90 if(mid>=x) update(x,y,z,lson); 91 if(mid<y) update(x,y,z,rson); 92 pushup(rt); 93 } 94 LL query(int x,int y,lrrt){ 95 if(x<=L&&R<=y) return tree[rt].value; 96 imid; 97 pushdown(rt); 98 LL big=-inf; 99 if(mid>=x) big=max(big,query(x,y,lson)); 100 if(mid<y) big=max(big,query(x,y,rson)); 101 return big; 102 } 103 void solve(){ 104 init(); 105 Index=0; 106 dfs(0,-1); 107 for(int i=0;i<n;i++){ 108 dist[i]=a[i]; 109 } 110 dfs_for_dist(0,-1); 111 build(iall); 112 for(int i=0;i<n;i++){ 113 #ifdef debug 114 printf("i=%d l=%d r=%d\n",i,node[i].l,node[i].r); 115 #endif // debug 116 update(node[i].l,node[i].l,dist[i],iall); 117 } 118 answer.clear(); 119 for(int i=0;i<m;i++){ 120 if(q[i].type){ 121 int u=q[i].x; 122 answer.push_back(query(node[u].l,node[u].r,iall)); 123 } 124 else{ 125 int u=q[i].x; 126 LL d=q[i].y-a[u]; 127 a[u]=q[i].y; 128 update(node[u].l,node[u].r,d,iall); 129 } 130 } 131 } 132 int main(){ 133 int t; 134 while(~scanf("%d",&t)){ 135 int cas=1; 136 while(t--){ 137 scanf("%d%d",&n,&m); 138 for(int i=0;i<n-1;i++){ 139 scanf("%d%d",&e[i].u,&e[i].v); 140 } 141 for(int i=0;i<n;i++){ 142 scanf("%d",&a[i]); 143 } 144 for(int i=0;i<m;i++){ 145 scanf("%d%d",&q[i].type,&q[i].x); 146 if(q[i].type==0){ 147 scanf("%I64d",&q[i].y); 148 } 149 } 150 solve(); 151 printf("Case #%d:\n",cas++); 152 for(int i=0;i<answer.size();i++){ 153 printf("%I64d\n",answer[i]); 154 } 155 } 156 } 157 return 0; 158 }
http://acm.hdu.edu.cn/showproblem.php?pid=5695
题意:n个人排队 ,给出m对点,表示u 不希望 v 排在自己前面, 每个人的得分是前面包括自己在内id的最小值。求一个排列,满足要求,且总分最高。
解法:u-》v建一条有向边 ,拓扑排序的结果就是一个合法的解。要使得总分高,那么当有多个可以排队的情况下,贪心选取id大的先排会使得得分大。
1 #include<cstdio> 2 #include<vector> 3 #include<queue> 4 using namespace std; 5 typedef long long LL; 6 const int M=1e5+10; 7 int t,n,m; 8 struct E{ 9 int u,v; 10 }e[M]; 11 int d[M]; 12 int answer[M]; 13 vector<int> g[M]; 14 priority_queue<int> q; 15 void init(){ 16 for(int i=1;i<=n;i++){ 17 d[i]=0; 18 g[i].clear(); 19 } 20 for(int i=0;i<m;i++){ 21 g[e[i].u].push_back(e[i].v); 22 d[e[i].v]++; 23 } 24 } 25 LL solve(){ 26 init(); 27 while(!q.empty()) q.pop(); 28 for(int i=1;i<=n;i++){ 29 if(!d[i]){ 30 q.push(i); 31 } 32 } 33 int la=0; 34 while(!q.empty()){ 35 int u=q.top(); 36 q.pop(); 37 answer[la++]=u; 38 for(int i=0;i<g[u].size();i++){ 39 int v=g[u][i]; 40 d[v]--; 41 if(!d[v]){ 42 q.push(v); 43 } 44 } 45 } 46 LL sum=0; 47 int small=n+1; 48 for(int i=0;i<n;i++){ 49 small=min(small,answer[i]); 50 sum+=small; 51 } 52 return sum; 53 } 54 int main(){ 55 while(~scanf("%d",&t)){ 56 while(t--){ 57 scanf("%d%d",&n,&m); 58 for(int i=0;i<m;i++){ 59 scanf("%d%d",&e[i].u,&e[i].v); 60 } 61 printf("%lld\n",solve()); 62 } 63 } 64 return 0; 65 }
end