码迷,mamicode.com
首页 > 编程语言 > 详细

HDU 5156 - Harry and Christmas tree (dfs序+离线树状数组)

时间:2015-03-06 00:53:38      阅读:523      评论:0      收藏:0      [点我收藏+]

标签:

http://acm.hdu.edu.cn/showproblem.php?pid=5156

BC#25的C题。

题意是:给出一颗大小为n的树,以1为根,然后给出m次染色,每次将节点u加上一种颜色(一个节点可以有多个颜色)。

最后查询树上每个节点对应子树上包含的不同颜色数量。

 

当时这场比赛没有做,回来看一下题目,没看标解就试着敲了一遍,于是解题思路从一开始就走上了不归路。

标解是O(n+m)的方法,主要思路是将问题转为:一次染色表示将u到根节点的路径都染上这种颜色。

但这样做需要去重,因为如果u和v都被染过某种颜色,那么他们的lca及其父链会被多染一次这种颜色。

于是用到了离线tarjan,一次对所有两两相同颜色节点的lca去重(减去1次染色)。

排序的地方都用基数排序,于是复杂度则为线性的。

 

这次做的时候没有想到上述标解线性的算法,

想到的方法是直接对树做一遍dfs序,所有的节点都替换为该节点上染的颜色序列,然后即可求出每个节点对应的子树的在dfs序列中的区间(子树上的节点在dfs序中一定是连续的)。

于是这道题被赤裸裸地转化为区间不同数字数量的查询,参见SPOJ - DQUERY : http://www.spoj.com/problems/DQUERY/

关于这个问题有两种方法,一种是离线树状数组,一种是在此基础上改为在线的主席树,具体不多展开,有众多题解可以参考。

主席树的方法在这里会妥妥地MLE, 于是这里采用离线树状数组的方法。

 

由于这个序列的长度最多为m,所以就实现了一个mlogm的算法(目测好容易超时啊 = =)。

最后用快速读入,并且将每个节点上重复的颜色去重了才过掉这道题,2400ms,危险飘过。

回头看代码的时候发现记录上一个数字出现位置的时候不需要用map,直接用数组就可以,于是优化了一下,最后900ms。

 

  1 #include <iostream>
  2 #include <sstream>
  3 #include <ios>
  4 #include <iomanip>
  5 #include <functional>
  6 #include <algorithm>
  7 #include <vector>
  8 #include <string>
  9 #include <list>
 10 #include <queue>
 11 #include <deque>
 12 #include <stack>
 13 #include <set>
 14 #include <map>
 15 #include <cstdio>
 16 #include <cstdlib>
 17 #include <cmath>
 18 #include <cstring>
 19 #include <climits>
 20 #include <cctype>
 21 using namespace std;
 22 #define XINF INT_MAX
 23 #define INF 0x3FFFFFFF
 24 #define MP(X,Y) make_pair(X,Y)
 25 #define PB(X) push_back(X)
 26 #define REP(X,N) for(int X=0;X<N;X++)
 27 #define REP2(X,L,R) for(int X=L;X<=R;X++)
 28 #define DEP(X,R,L) for(int X=R;X>=L;X--)
 29 #define CLR(A,X) memset(A,X,sizeof(A))
 30 #define IT iterator
 31 #define RIT reverse_iterator
 32 typedef long long ll;
 33 typedef unsigned long long ull;
 34 typedef pair<int,int> PII;
 35 typedef vector<PII> VII;
 36 typedef vector<int> VI;
 37 #define X first
 38 #define Y second
 39 #define lson(X) ((X)<<1)
 40 #define rson(X) ((X)<<1|1)
 41 
 42 int Scan()
 43 {
 44     int res, ch=0;
 45     while(!(ch>=0&&ch<=9)) ch=getchar();
 46     res=ch-0;
 47     while((ch=getchar())>=0&&ch<=9)
 48         res=res*10+ch-0;
 49     return res;
 50 }
 51 
 52 void Out(int a)
 53 {
 54     if(a>9)
 55         Out(a/10);
 56     putchar(a%10+0);
 57 }
 58 
 59 
 60 int c[500010];
 61 int N;
 62 
 63 void init(int n) {
 64     N = n;
 65     REP(i,N+1) c[i]=0;
 66 }
 67 
 68 void add(int i, int x) {
 69     while(i<=N) {
 70         c[i]+=x;
 71         i+=i&-i;
 72     }
 73 }
 74 
 75 int sum(int i) {
 76     int r=0;
 77     while(i) {
 78         r+=c[i];
 79         i-=i&-i;
 80     }
 81     return r;
 82 }
 83 
 84 int a[500010];
 85 
 86 int ans[50000];
 87 VII query[500010];
 88 
 89 VI Map[50000];
 90 int vis[50000];
 91 int s[50000], e[50000];
 92 VI vec[50000];
 93 
 94 int tot=0;
 95 void dfs(int u) {
 96     vis[u]=1;
 97     s[u]=tot;
 98     REP(i,vec[u].size()) a[tot++]=vec[u][i];
 99     REP(i,Map[u].size()) {
100         int v=Map[u][i];
101         if(!vis[v]) dfs(v);
102     }
103     e[u]=tot-1;
104 }
105 
106 int mp[100001]; // 此处如果改用map会慢很多 
107 
108 int main() {
109     int n,m,l,r,u,v;
110     while(~scanf("%d%d",&n,&m)) {
111         REP(i,50000) Map[i].clear();
112         REP(i,50000) vec[i].clear();
113         REP(i,n-1) {
114             u=Scan(); v=Scan();
115             u--; v--;
116             Map[u].PB(v);
117             Map[v].PB(u);
118         }
119         REP(i,m) {
120             u=Scan(); v=Scan();
121             u--;
122             vec[u].PB(v);
123         }
124         /* 对一个节点上的颜色去重 
125         REP(i,n) {
126             sort(vec[i].begin(),vec[i].end());
127             vec[i].erase(unique(vec[i].begin(),vec[i].end()),vec[i].end());
128         }
129         */
130         tot=1;
131         CLR(vis,0);
132         dfs(0);
133         
134         REP(i,tot) query[i].clear();
135         REP(i,n) query[s[i]].PB(MP(e[i],i));
136         //map<int,int> mp;
137         CLR(mp,-1);
138         init(tot);
139         DEP(i,tot,1) {
140             add(i,1);
141             if(mp[a[i]]!=-1) add(mp[a[i]],-1);
142             REP(j,query[i].size()) {
143                 ans[query[i][j].Y] = sum(query[i][j].X);
144             }
145             mp[a[i]]=i;
146         }
147         REP(i,n) {
148             if(i) putchar( );
149             Out(ans[i]);
150         }
151         putchar(\n);
152     }
153     return 0;
154 }

 

HDU 5156 - Harry and Christmas tree (dfs序+离线树状数组)

标签:

原文地址:http://www.cnblogs.com/curs0r/p/4317001.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!