bzoj 2286: [Sdoi2011消耗战

  1 #include<cstdio>
  2 #include<iostream>
  3 #define M 1000009
  4 #define N 250009
  5 #define ll long long
  6 #define inf 1000000000000000000LL
  7 #include<algorithm>
  8 using namespace std;
  9 int n,head[N],next[M],u[M],cnt,fa[N][22],deep[N],m,h[N],dfn[N],TI,cnt1,zhan[N],tot,head1[N];
 10 int next1[M],u1[M],v[M];
 11 ll mn[N],f[N];
 12 void jia(int a1,int a2,int a3)
 13 {
 14     cnt++;
 15     next[cnt]=head[a1];
 16     head[a1]=cnt;
 17     u[cnt]=a2;
 18     v[cnt]=a3;
 19     return;
 20 }
 21 void jia2(int a1,int a2)
 22 {
 23     if(a1==a2)
 24       return;
 25     cnt1++;
 26     next1[cnt1]=head1[a1];
 27     head1[a1]=cnt1;
 28     u1[cnt1]=a2;
 29     return;
 30 }
 31 void dfs(int a1)
 32 {
 33     dfn[a1]=++TI;
 34     for(int i=1;(1<<i)<=deep[a1];i++)
 35       fa[a1][i]=fa[fa[a1][i-1]][i-1];
 36     for(int i=head[a1];i;i=next[i])
 37       if(u[i]!=fa[a1][0])
 38         {
 39             deep[u[i]]=deep[a1]+1;
 40             fa[u[i]][0]=a1;
 41             mn[u[i]]=min(mn[a1],(ll)v[i]);
 42             dfs(u[i]);
 43         }
 44 }
 45 bool cmp(int a1,int a2)
 46 {
 47     return dfn[a1]<dfn[a2];
 48 }
 49 int lca(int a1,int a2)
 50 {
 51     if(deep[a1]<deep[a2])
 52       swap(a1,a2);
 53     int a3=deep[a1]-deep[a2];
 54     for(int i=0;i<=20;i++)
 55       if(a3&(1<<i))
 56         a1=fa[a1][i];
 57     for(int i=20;i>=0;i--)
 58       if(fa[a1][i]!=fa[a2][i])
 59         {
 60             a1=fa[a1][i];
 61             a2=fa[a2][i];
 62         }
 63     if(a1==a2)
 64       return a1;
 65     return fa[a1][0];
 66 }
 67 void dp(int a1)
 68 {
 69     ll tmp=0;
 70     f[a1]=mn[a1];
 71     for(int i=head1[a1];i;i=next1[i])
 72       {
 73         dp(u1[i]);
 74         tmp+=f[u1[i]];
 75       }
 76     head1[a1]=0;
 77     if(tmp<f[a1]&&tmp)
 78       f[a1]=tmp;
 79     return;
 80 }
 81 void solve()
 82 {
 83     cnt1=0;
 84     scanf("%d",&h[0]);
 85     for(int i=1;i<=h[0];i++)
 86       scanf("%d",&h[i]);
 87     sort(h+1,h+h[0]+1,cmp);
 88     int tot=0;
 89     h[++tot]=h[1];
 90     for(int i=2;i<=h[0];i++)
 91         if(lca(h[tot],h[i])!=h[tot])h[++tot]=h[i];
 92     h[0]=tot;
 93     tot=0;
 94     zhan[++tot]=1;
 95     for(int i=1;i<=h[0];i++)
 96       {
 97         int f=lca(h[i],zhan[tot]);
 98         for(;1;)
 99           {
100             if(deep[f]>=deep[zhan[tot-1]])
101               {
102                   jia2(f,zhan[tot]);
103                   tot-=1;
104                   if(zhan[tot]!=f)
105                     {
106                             tot+=1;
107                             zhan[tot]=f;
108                      }
109                   break;
110               }
111             jia2(zhan[tot-1],zhan[tot]);
112             tot-=1;
113           }
114         if(h[i]!=zhan[tot])
115            {
116             tot+=1;
117               zhan[tot]=h[i];
118            }
119       }
120     for(;tot>1;jia2(zhan[tot-1],zhan[tot]),tot--);
121     dp(1);
122     printf("%lld\n",f[1]);
123     return;
124 }
125 int main()
126 {
127     scanf("%d",&n);
128     for(int i=1;i<n;i++)
129       {
130         int a1,a2,a3;
131         scanf("%d%d%d",&a1,&a2,&a3);
132         jia(a1,a2,a3);
133         jia(a2,a1,a3);
134       }
135     mn[1]=inf;
136     dfs(1);
137     scanf("%d",&m);
138     for(int i=1;i<=m;i++)
139       solve();
140     return 0;
141 }

显然想到DP,然而DP超时,这个题是构建虚树,然后DP。

时间: 2024-10-19 14:41:46

bzoj 2286: [Sdoi2011消耗战的相关文章

bzoj 2286 [Sdoi2011]消耗战(虚树+树上DP)

2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1276  Solved: 445[Submit][Status][Discuss] Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望.已知在其他k个岛屿上有丰富能源,为了防止敌军获取能源,我军的任务是炸

BZOJ 2286: [Sdoi2011消耗战 [DP 虚树]

传送门 题意: 删除价值和最小的边使得$1$号点与$k$个关键点不连通 一个树形DP...但是询问多次,保证总的关键点数为$O(n)$ 先说一下这个$DP$ $f[i]$表示子树$i$中的关键点与$1$不连通的最小价值 如果$i$是关键点则必须删除$i$到$1$的权值最小的边,否则$\sum f[child\ of\ i]$ 学了一下虚树...找不到别的资料啊只有别人的$Blog$ 试验了好多写法 貌似其中有好多带$Bug$的写法 最终定下了现在的版本应该是没大有问题的吧...明天再做两道虚树,

BZOJ 2286 SDOI2011 消耗战 倍增LCA+单调栈

题目大意:给定一棵树,边上有边权,m次询问,每次选定一些关键点,求将1号节点与所有关键点都切断所需的最小花销 关键点的总数<=50W 首先我们考虑暴力想法 令f[x]表示切断以x为根的子树中所有关键点的最小花销 g[x]表示x是不是关键点 那么对于x的每个子节点y有f[x]=Σmin(g[y]?INF:f[y],Distance(x,y) ) 这样每次暴力做一遍树形DP,时间复杂度是O(n*m)的 现在由于每次询问的点数不一定会达到n的级别,对所有节点进行DFS非常浪费 我们可以将询问的关键点拿

BZOJ 2286 [Sdoi2011]消耗战

题解:对询问点建立虚树 然后在虚树上Dp 每个点父边边权为这个点到根的边权最小值 一开始学了假的虚树 一开始竟然没想到父边边权可以这样赋 #include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<queue> #include<algorithm> using namespace std; const int maxn=500009;

[Sdoi2011]消耗战

2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 3108  Solved: 1115[Submit][Status][Discuss] Description 在 一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经 没有足够多的能源维系战斗,我军胜利在望.已知在其他k个岛屿上有丰富能源,为了防止敌军获取能源,我军的任

BZOJ 2243: [SDOI2011]染色 树链剖分

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1886  Solved: 752[Submit][Status] Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写一个程序依次完成这m个操作. In

AC日记——[SDOI2011]消耗战 洛谷 P2495

[SDOI2011]消耗战 思路: 建虚树走树形dp: 代码: #include <bits/stdc++.h> using namespace std; #define INF 1e17 #define maxn 250005 #define ll long long #define maxm (maxn<<1) struct LandType { ll id,key; bool operator<(const LandType pos)const { return key

luogu P2495 [SDOI2011]消耗战

二次联通门 : luogu P2495 [SDOI2011]消耗战 /* luogu P2495 [SDOI2011]消耗战 虚树+树形dp 首先对原图构建出虚树 在建图的时候处理出最小值 转移即可 小技巧 在dp的过程中可以顺便把边表清空 将边结构体封装可方便的建多张图 */ #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #define INF 1

【BZOJ2286】[Sdoi2011]消耗战 虚树

[BZOJ2286][Sdoi2011]消耗战 Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望.已知在其他k个岛屿上有丰富能源,为了防止敌军获取能源,我军的任务是炸毁一些桥梁,使得敌军不能到达任何能源丰富的岛屿.由于不同桥梁的材质和结构不同,所以炸毁不同的桥梁有不同的代价,我军希望在满足目标的同时使得总代价最小. 侦查部门还发现,敌军有