• loj2163 / bzoj2212 / P3521 [POI2011]ROT-Tree Rotations(线段树合并)


    P3521 [POI2011]ROT-Tree Rotations

    loj2163 [POI2011]ROT-Tree Rotations(数据加强)

    (loj的数据套了个fread优化才过...)

    显然地,对于一棵线段树(树根设为$rt$),是否翻转它的子树的子树,对于跨$mid$的逆序对数量没有影响。

    那么我们可以层层统计(设左右子树为$lc,rc$):

    不翻转时,该层(跨$mid$)的逆序对:$a[a[a[rt].lc].rc].sum*a[a[a[rt].rc].lc].sum$

    翻转时,逆序对数量:$a[a[a[rt].lc].lc].sum*a[a[a[rt].rc].rc].sum$

    递归处理即可。


    重点是合并线段树:

    前提:两棵动态开点线段树

    实现(将树$pr$合并到$o$上):

    void merge(int &o,int pr){
        if(!o||!pr) {o=o+pr;return;}//一棵为空则返回另一边
        a[o].sum+=a[pr].sum;
        .......//结算信息
        merge(a[o].lc,a[pr].lc);
        merge(a[o].rc,a[pr].rc); //递归合并
    }

    蓝后就结束了。


     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cctype>
     5 #define re register
     6 using namespace std;
     7 typedef long long ll;
     8 char gc(){
     9     static char buf[100000],*p1=buf,*p2=buf;
    10     return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    11 }
    12 void read(int &x){
    13     char c=gc();x=0;
    14     while(!isdigit(c)) c=gc();
    15     while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=gc();
    16 }//以上读入优化
    17 ll min(ll &a,ll &b){return a<b?a:b;}
    18 struct node{int sum,lc,rc;}a[4000005];
    19 int n,u,rt; ll res1,res2,ans;
    20 void update(int &o,int l,int r,int v){
    21     if(!o) o=++u;
    22     ++a[o].sum;
    23     if(l==r) return;
    24     int mid=l+((r-l)>>1);
    25     if(v<=mid) update(a[o].lc,l,mid,v);
    26     else update(a[o].rc,mid+1,r,v);
    27 }
    28 void merge(int &o,int pr){//把o/pr当作左/右子树,合并到左子树
    29     if(!o||!pr) {o=o+pr;return;}
    30     a[o].sum+=a[pr].sum;
    31     res1+=1ll*a[a[o].lc].sum*a[a[pr].rc].sum; //翻转:lc->lc 和 rc->rc 之间的逆序对数
    32     res2+=1ll*a[a[o].rc].sum*a[a[pr].lc].sum; //不翻转:lc->rc 和 rc->lc 之间的逆序对数
    33     merge(a[o].lc,a[pr].lc); //合并线段树,并计算 lc->lc 和 rc->lc 之间的逆序对数
    34     merge(a[o].rc,a[pr].rc); //同上
    35 }
    36 void dfs(int &x){//题意的神奇递归输入
    37     int q,lc,rc; read(q);
    38     if(!q){
    39         dfs(lc); dfs(rc);
    40         res1=res2=0;
    41         merge(x=lc,rc);//合并
    42         ans+=min(res1,res2);//选代价小的
    43     }else update(x=0,1,n,q);//给叶子结点单独建一棵线段树,后面再合并
    44 }
    45 int main(){
    46 //    freopen("P3521_2.in","r",stdin);
    47     read(n); dfs(rt);
    48     printf("%lld",ans);
    49     return 0;
    50 } 
    View Code
  • 相关阅读:
    css设置兼容的透明样式
    mybatis 使用oracle merge into 语句踩坑实录
    eclipse导入SVN上的Maven多模块项目
    jquery.form插件中动态修改表单数据
    java的几种对象(po,dto,dao等)
    redis面试总结
    前段面试准备
    查询各科成绩最好的学生
    Github访问慢解决办法
    该文件有程序在使用
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/9839694.html
Copyright © 2020-2023  润新知