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 }
View Code

 

 

 

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 }
View Code

 

 

 

end

转载于:https://www.cnblogs.com/gaolzzxin/p/5515419.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值