zoukankan      html  css  js  c++  java
  • 洛谷 P1600 天天爱跑步

    https://www.luogu.org/problemnew/show/P1600

    (仅做记录)

    自己的假方法:

    每一次跑从a到b:
    设l=lca(a,b)
    对于以下产生贡献:

    a到l的链上所有的点(x)满足
    dep[x]+w[x]==dep[a]

    l到b的链上(不含l)所有的点(x)满足
    dep[x]-dep[l]+dep[a]-dep[l]==w[x]
    即dep[x]-w[x]==2*dep[l]-dep[a]

    于是每一个点记两个map<int,int>,其中键值对(p,q)表示

    “从该点到根的路径上所有满足 dep[x]+w[x]==p(第一个map) / dep[x]-w[x]==p(第二个map) 的点的答案都要加上q"

    每一次跑,就是树上差分,乱搞一下。。。

    最后每个点x的答案就是以其为根的子树中所有点的两个map分别合并起来后(两个map里面分别有(p,q1)和(p,q2),则合并后有(p,q1+q2)),

    在这两个map里面分别查询dep[x]+w[x]和dep[x]-w[x]得到答案的和

    因此可以启发式合并处理一下

    把平衡树换成值域线段树,启发式合并换成线段树合并就是一个log了。。。。。

    曾经错误:线段树节点作死不开垃圾回收,空间可能算不太对了,原来开7000000都RE了

      1 #include<cstdio>
      2 #include<algorithm>
      3 using namespace std;
      4 int ll=-300000,rr=600000;
      5 namespace SegT
      6 {
      7 int dat[20000100],lc[20000100],rc[20000100],mem;
      8 int L,x;
      9 #define mid (l+((r-l)>>1))
     10 void _addx(int l,int r,int &num)
     11 {
     12     if(!num)    num=++mem;
     13     if(l==r)    {dat[num]+=x;return;}
     14     if(L<=mid)    _addx(l,mid,lc[num]);
     15     else    _addx(mid+1,r,rc[num]);
     16     dat[num]=dat[lc[num]]+dat[rc[num]];
     17 }
     18 int merge(int a,int b)
     19 {
     20     if(!a||!b)    return a+b;
     21     dat[a]+=dat[b];
     22     lc[a]=merge(lc[a],lc[b]);
     23     rc[a]=merge(rc[a],rc[b]);
     24     //delnode(b)
     25     return a;
     26 }
     27 int _query(int l,int r,int num)
     28 {
     29     if(l==r)    return dat[num];
     30     if(L<=mid)    return _query(l,mid,lc[num]);
     31     else    return _query(mid+1,r,rc[num]);
     32 }
     33 void addx(int pos,int dat,int &num)
     34 {
     35     L=pos;x=dat;_addx(ll,rr,num);
     36 }
     37 int query(int pos,int &num)
     38 {
     39     L=pos;return _query(ll,rr,num);
     40 }
     41 #undef mid
     42 }
     43 using SegT::addx;using SegT::query;using SegT::merge;
     44 struct E
     45 {
     46     int to,nxt;
     47 }e[600100];
     48 int f1[300100],ne;
     49 int w[300100],rt1[300100],rt2[300100];
     50 int n,m;
     51 namespace LCA
     52 {
     53     int anc[300100][22],log2n,dep[300100];
     54     void dfs(int u,int fa)
     55     {
     56         int i,k;
     57         anc[u][0]=fa;
     58         for(i=1;i<=log2n;i++)    anc[u][i]=anc[anc[u][i-1]][i-1];
     59         for(k=f1[u];k;k=e[k].nxt)
     60             if(e[k].to!=fa)
     61             {
     62                 dep[e[k].to]=dep[u]+1;
     63                 dfs(e[k].to,u);
     64             }
     65     }
     66     int lca(int a,int b)
     67     {
     68         if(dep[a]<dep[b])    swap(a,b);
     69         int t=dep[a]-dep[b],i;
     70         for(i=log2n;i>=0;i--)
     71             if((1<<i)<=t)
     72                 t-=(1<<i),a=anc[a][i];
     73         if(a==b)    return a;
     74         for(i=log2n;i>=0;i--)
     75             if(anc[a][i]!=anc[b][i])
     76                 a=anc[a][i],b=anc[b][i];
     77         return anc[a][0];
     78     }
     79 }
     80 using LCA::lca;using LCA::dep;
     81 int ans[300100];
     82 void dfs(int u,int fa)
     83 {
     84     int k;
     85     for(k=f1[u];k;k=e[k].nxt)
     86         if(e[k].to!=fa)
     87         {
     88             dfs(e[k].to,u);
     89             rt1[u]=merge(rt1[u],rt1[e[k].to]);
     90             rt2[u]=merge(rt2[u],rt2[e[k].to]);
     91         }
     92     ans[u]=query(dep[u]+w[u],rt1[u])+query(dep[u]-w[u],rt2[u]);
     93 }
     94 int main()
     95 {
     96     int i,a,b,l;
     97     scanf("%d%d",&n,&m);
     98     for(i=1;i<n;i++)
     99     {
    100         scanf("%d%d",&a,&b);
    101         e[++ne].to=b;e[ne].nxt=f1[a];f1[a]=ne;
    102         e[++ne].to=a;e[ne].nxt=f1[b];f1[b]=ne;
    103     }
    104     for(i=1;i<=n;i++)    scanf("%d",&w[i]);
    105     while((1<<(LCA::log2n+1))<=n)    LCA::log2n++;
    106     LCA::dfs(1,0);
    107     while(m--)
    108     {
    109         scanf("%d%d",&a,&b);l=lca(a,b);
    110         addx(dep[a],1,rt1[a]);addx(dep[a],-1,rt1[LCA::anc[l][0]]);
    111         addx(2*dep[l]-dep[a],1,rt2[b]);addx(2*dep[l]-dep[a],-1,rt2[l]);
    112     }
    113     dfs(1,0);
    114     for(i=1;i<=n;i++)    printf("%d ",ans[i]);
    115     return 0;
    116 }

    别人的做法(大概写一下):

    先把每个点x答案换一下形式:"以x为根的子树中有多少个起点/终点满足对应条件"

    dfs(x)时,先dfs(所有子节点),然后统计自身答案,然后把自身点满足的性质(比如,是起点,是终点,是某一对起点与终点的lca,是某一对起点与终点的lca的父亲)(可以预处理出来)产生的贡献加进一个全局的贡献数组里面

  • 相关阅读:
    ASP.NET MVC基于标注特性的Model验证:DataAnnotationsModelValidator
    TDD个人实践体会
    客户端调用Spring.Net发布的WebService
    XML自动解析器开源
    Javascript MVVM模式前端框架—Knockout 2.1.0系列
    定时执行SQL存储过程
    orchard之lucene.net索引生成
    并发编程学习总结
    python开发总结
    Thrift
  • 原文地址:https://www.cnblogs.com/hehe54321/p/9006324.html
Copyright © 2011-2022 走看看