zoukankan      html  css  js  c++  java
  • 树上二分

    http://codeforces.com/contest/740/problem/D

    相同的一道题目:http://codeforces.com/gym/101147/problem/J

    读完题目,暴力的写法很容易写出来,对于每一个点,不断往父节点找,直到没有父节点,或者不满足条件直接跳出。就是这里:dis(u,v) <= a[v],这里,不断往上父节点,dis是严格单调递增的,同时a保持不变,所以可以考虑二分,我没做出来,我做的时候,也分析出这个性质,想到应该用sparse table,但是这个区间内的每个节点都要加1,我不知道怎么加快这个过程,那就是还要遍历,跟暴力的复杂度差不多,但是,确实有trick可以高效的实现!考虑区间端点+1和-1,这不跟统计线段的重叠最大次数的套路是一样的么,感觉自己还是不能灵活应用。然后从根节点开始,通过dfs收集所有儿子节点的和,就是最终的结果。比如 0 -1 0 1这条路径,最后的结果就是0, 0, 1, 1,路径上的1和-1合并,对这个区间外的值,没有影响。好像哪里也见过这个套路,好像是,统计区间内只出现一次的数的个数。套路,方法是一致的。

    总结几点:

    1. 看到单调的性质,或者这样(000000111或者1110000000)这样,1代表满足条件,0代表不满足,要立马想到二分。非常重要。

    2. sparse table的数据结构要熟练的写出来。经典的应用是区间查询,本质还是二分。rmq。父节点的父节点,怎么二分,怎么找lca,都要搞清楚。lca的离线rmq算法。

    3. 最后统计区间的个数的trick,+1, -1,还是没有分析清楚。后面需要进一步学习。

    这道题目,还有其他的做法,就是变换条件dis(u,v) <= a[v], => dis(v) - dis(u) <= a[v] => dis(v) - a[v] <= dis(u) 这里v是u的儿子节点,构造dfs访问顺序,儿子节点的顺序在(in[u], out[u])之间,需要统计这个区间内满足上面条件的点的个数。好像一般统计小于某个值的节点个数,都是提前排好序,按照从小到大的顺序,然后查询的时候只需要查询区间的元素个数既可以,而区间查询可以采取线段树,树状数组来做(好像不知道怎么高效的查询区间内小于某一个值的元素的个数),然后就结束了。 一般多个变量,固定几个变量,寻找一个随意变量,而这个变量可以通过二分等logn高效的方法实现,来进行加速。

    贴一下代码,这里贴的都是别人的代码,遇到类似的问题,可以直接拿出来使用。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <algorithm>
     4 #include <vector>
     5 #include <string>
     6 #include <cstring>
     7 #include <map>
     8 #include <set>
     9 #include <bitset>
    10 #include <cassert>
    11 #include <cstdlib>
    12 #include <ctime>
    13 #include <unordered_map>
    14 using namespace std;
    15 
    16 #define PB(x) push_back(x)
    17 #define SZ(x) ((int)(x).size())
    18 #define ERR(x) cout << #x" = " << x << "  "
    19 #define NL cout << endl
    20 #define ALL(x) (x).begin(), (x).end()
    21 #define X first
    22 #define Y second
    23 typedef long long llint;
    24 
    25 const int N = 200100, LOG = 21;
    26 typedef pair<int,int> pii;
    27 int n, a[N], par[N][LOG];
    28 vector<pii> g[N];
    29 llint dep[N];
    30 int z[N], ans[N];
    31 
    32 inline void dfs(int v, int p, llint d){
    33     dep[v] = d; par[v][0] = p;
    34     for (pii p: g[v])
    35         dfs(p.X, v, d + 1LL*p.Y);
    36 }
    37 
    38 inline void solve(int u){
    39     int v = u;
    40     for (int j = LOG-1; j >= 0; j--)
    41         if (par[v][j] != -1 && (dep[u] - dep[par[v][j]]) <= 1LL*a[u])
    42             v = par[v][j];
    43     z[u]++;
    44     if (par[v][0] != -1) z[par[v][0]]--;
    45 }
    46 
    47 inline int go(int v){
    48     int res = z[v];
    49     for (pii p: g[v]){
    50         res += go(p.X);
    51     }
    52     return ans[v] = res;
    53 }
    54 
    55 int main(){
    56     scanf("%d", &n);
    57     for (int i = 1; i <= n; i++)
    58         scanf("%d", a+i);
    59     int p, w;
    60     for (int i = 1; i < n; i++){
    61         scanf("%d%d", &p, &w);
    62         g[p].PB(pii(i+1, w));
    63     }
    64     memset(par, -1, sizeof par);
    65     dfs(1, -1, 0);
    66     for (int j = 1; j < LOG; j++)
    67         for (int i = 1; i <= n; i++)
    68             par[i][j] = (par[i][j-1] == -1) ? -1 : par[par[i][j-1]][j-1];
    69     for (int i = 1; i <= n; i++)
    70         solve(i);
    71     go(1);
    72     for (int i = 1; i <= n; i++) printf("%d ", ans[i]-1);
    73 
    74      return 0;
    75 }

    第二种解法

     1 #include <bits/stdc++.h>
     2 using namespace std; 
     3 
     4 const int N=1e6;
     5 const int Mod=1e9+7;
     6 
     7 long long dis[N];
     8 int n,m,a[N],p[N],w[N],ans[N],in[N],out[N],ord;
     9 vector<int> E[N],W[N];
    10 
    11 void dfs(int x,long long y) {
    12     dis[x]=y;
    13     in[x]=++ord;
    14     for(int i=0;i<E[x].size();i++) {
    15         dfs(E[x][i],y+W[x][i]);
    16     }    
    17     out[x]=ord;
    18 }
    19 
    20 struct Node {
    21     int t,id;
    22     long long v;
    23     Node(){}
    24     Node(int t1,int id1,long long v1) {
    25         t=t1; id=id1; v=v1;
    26     } 
    27     bool operator < (const Node &a) const {
    28         if(v==a.v) return t<a.t;
    29         return v<a.v; 
    30     }
    31 }Q[N];
    32 
    33 int cnt,B[N];
    34 
    35 inline void Ins(int x) {
    36     while(x<=n) {
    37         B[x]++;
    38         x+=x&-x;
    39     }
    40 }
    41 
    42 inline int ask(int x) {
    43     int res=0;
    44     while(x) {
    45         res+=B[x];
    46         x-=x&-x;
    47     }
    48     return res;
    49 }
    50 
    51 int main() {
    52     cin>>n;
    53     for(int i=1;i<=n;i++) scanf("%d",a+i);
    54     for(int i=2;i<=n;i++) {
    55         scanf("%d%d",p+i,w+i);
    56         E[p[i]].push_back(i);
    57         W[p[i]].push_back(w[i]);
    58     } //cout<<"/";
    59     dfs(1,0); //cout<<"/";
    60     for(int i=1;i<=n;i++) {
    61         Q[++cnt]=Node(1,i,dis[i]-a[i]);
    62         Q[++cnt]=Node(2,i,dis[i]);
    63     }
    64     sort(Q+1,Q+1+cnt);
    65     for(int i=1;i<=cnt;i++) {
    66         if(Q[i].t==1) {
    67             Ins(in[Q[i].id]);
    68         } else {
    69             ans[Q[i].id]=ask(out[Q[i].id])-ask(in[Q[i].id]-1);
    70         }
    71     }
    72     for(int i=1;i<=n;i++) printf("%d ",ans[i]-1);
    73 }
  • 相关阅读:
    xls10-Python3安装cx_Oracle连接oracle数据库实操总结list
    xls3-2-想要使用Python的xlwt设置单元格的背景色
    XLS9-PyCharm下打包*.py程序成.exe
    XLS8-python3+PyQt5+pycharm桌面GUI开发
    epoll模型中LT、ET模式分析
    lambda函数也叫匿名函数,即,函数没有具体的名称。先来看一个最简单例子:
    xls7-python读conf配置文件--ConfigParser
    xls6-python解析properties文件
    xls5-解析properties文件,在python中基本没有遇到
    xls2- 用Python读写Excel文件-乘法口诀
  • 原文地址:https://www.cnblogs.com/y119777/p/6102126.html
Copyright © 2011-2022 走看看