zoukankan      html  css  js  c++  java
  • 「Luogu P3521 [POI2011]ROT-Tree Rotations」

    题目大意

    给出一颗有 (n) 个叶节点的二叉树,且对于所有非叶节点都有两个儿子,每次操作可以交换任意节点的两个儿子,最终要使得先序遍历后叶节点的逆序对最少,输出这个最小值.

    分析

    考虑交换某个节点的两个儿子对最终答案的影响,交换之后对于子树内的逆序对并不会产生影响,对这颗子树树以外的逆序对也不会产生影响,所以产生的影响只有两颗子树.那么只需要考虑哪棵子树放前面更优就好了.

    考虑用权值线段树来维护每个数出现的次数,考虑合并的时候同时计算出两种情况所产生的逆序对个数.

    那么考虑如何快速计算左右子树的两种摆放方式的逆序对个数.可以发现在合并的时候会遍历两子树中区间内都非空很多区间,那么可以通过乘法原理来计算逆序对.

    代码

    #include<bits/stdc++.h>
    #define REP(i,first,last) for(int i=first;i<=last;++i)
    #define DOW(i,first,last) for(int i=first;i>=last;--i)
    using namespace std;
    const int MAXN=2e5+5;
    const int MAX_NUM=2e5;
    const int INF=1e9;
    int n;
    long long answer=0;
    long long minll(long long a,long long b)
    {
    	if(a<b)
    	{
    		return a;
    	}
    	return b;
    }
    struct SegmentTree
    {
    	int lson,rson,sum;
    }sgt[MAXN*32];
    int sgt_cnt=0;
    int rubbish[MAXN*32],rubbish_cnt=0;
    #define LSON sgt[now].lson
    #define RSON sgt[now].rson
    #define MIDDLE ((left+right)>>1)
    #define LEFT LSON,left,MIDDLE
    #define RIGHT RSON,MIDDLE+1,right
    int NewPoint()//防止空间不足,写一个空间回收
    {
    	if(rubbish_cnt)
    	{
    		return rubbish[rubbish_cnt--];
    	}
    	return ++sgt_cnt;
    }
    void DeletePoint(int &now)
    {
    	sgt[now].lson=sgt[now].rson=0;
    	sgt[now].sum=0;
    	rubbish[++rubbish_cnt]=now;
    	now=0;
    }
    void PushUp(int now)//合并标记
    {
    	sgt[now].sum=sgt[LSON].sum+sgt[RSON].sum;
    }
    void Updata(int place,int &now,int left=1,int right=MAX_NUM)//单点修改
    {
    	if(place<left||right<place)
    	{
    		return;
    	}
    	if(!now)
    	{
    		now=NewPoint();
    	}
    	if(left==right)
    	{
    		sgt[now].sum++;
    		return;
    	}
    	Updata(place,LEFT);
    	Updata(place,RIGHT);
    	PushUp(now);
    }
    long long add_1,add_2;
    void Merge(int &tree1,int &tree2,int left=1,int right=MAX_NUM,bool first=1)//线段树合并
    {
    	if(first)
    	{
    		add_1=add_2=0;
    	}
    	if(!tree1||!tree2)
    	{
    		tree1+=tree2;
    		tree2=0;
    		return;
    	}
    	if(left==right)
    	{
    		sgt[tree1].sum+=sgt[tree2].sum;
    		DeletePoint(tree2);
    		return;
    	}
    	add_1+=1ll*sgt[sgt[tree1].rson].sum*sgt[sgt[tree2].lson].sum;//通过乘法原理计算逆序对
    	add_2+=1ll*sgt[sgt[tree1].lson].sum*sgt[sgt[tree2].rson].sum;
    	Merge(sgt[tree1].lson,sgt[tree2].lson,left,MIDDLE,0);//继续合并左右子树
    	Merge(sgt[tree1].rson,sgt[tree2].rson,MIDDLE+1,right,0);
    	DeletePoint(tree2);
    	PushUp(tree1);
    }
    #undef LSON
    #undef RSON
    #undef MIDDLE
    #undef LEFT
    #undef RIGHT
    struct Tree
    {
    	int lson,rson,now;
    }tree[MAXN];
    int tree_cnt=0;
    #define LSON tree[now].lson
    #define RSON tree[now].rson
    void DFS(int &root)//遍历全树
    {
    	int val;
    	scanf("%d",&val);
    	if(val)
    	{
    		Updata(val,root);//叶节点只要单点修改就好了
    		return;
    	}
    	int now=++tree_cnt;
    	DFS(LSON);
    	DFS(RSON);
    	Merge(LSON,RSON);//非叶节点需要合并子树
    	root=LSON;
    	answer+=minll(add_1,add_2);//并且加上逆序对更少的情况
    }
    #undef LSON
    #undef RSON
    int main()
    {
    	scanf("%d",&n);
    	int root=0;
    	DFS(root);
    	printf("%lld",answer);
    	return 0;
    }
    
  • 相关阅读:
    Python RabbitMQ
    对于一些概念的澄清
    Python没有执行__init__
    python中的gil是什么?
    linux命令行快捷键
    关于异步:再次思考和澄清
    greenlet代码解读
    关于协程
    设计模式-重复重复的设计模式
    组合模式-虚有其表的模式
  • 原文地址:https://www.cnblogs.com/Sxy_Limit/p/12631610.html
Copyright © 2011-2022 走看看