zoukankan      html  css  js  c++  java
  • HDU 5156

    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('
    ');
    152     }
    153     return 0;
    154 }
  • 相关阅读:
    C#------对SQLServer进行简单的增,删,改,查
    WinForm------点击Control弹出MessageBox
    WinForm------窗体初始化位置的显示
    WinForm------GridControl的部分属性介绍
    C#------编码规范
    vs------安装window net.framework 出现严重错误解决方法
    jsp------实现MD5加密
    jquery------捕获异常处理
    jquery------显示加载的js时出现中文乱码解决方法
    sublime3 常用功能总结
  • 原文地址:https://www.cnblogs.com/curs0r/p/4317001.html
Copyright © 2011-2022 走看看