bzoj2212(线段树合并第一道)

来源:互联网 发布:专车软件有哪些 编辑:程序博客网 时间:2024/05/17 08:18

 

话说像这样的,维护的东西需要数据结构且需要合并的问题,就可以考虑合并。例如本题,我们所需要从叶子节点把维护的数据不断递推上来,所以就需要线段树合并。

肯定是动态开节点

 

这样的题如果写平衡树启发式合并的话,就要带两个log,而线段树合并一个log就可以,虽然每一次合并复杂度不确定,我们考虑,对于每一次操作,都是把两个线段树合并,

而整个叶子节点共n颗线段树,每一颗只有一个元素,显然无论如何合并,n-1次之后我们就能将他们完全合。整个过程的复杂度不会比空树中插入n个整数来的大。

 

线段树合并关键是结构相同,所以我们可以把这个思想套在trie上

 

至于空间是n log n的!证明?

#include<cstdio>#include<cmath>#include<cstring>#include<algorithm>#include<iostream>#include<cstdlib>#include<stack>#include<utility>#define fi first#define se second#define MK(a,b) make_pair((a),(b))#define pii pair<int,ll>using namespace std;typedef long long ll;const int N=200005;inline int read(){int ans,f=1;char ch;while ((ch=getchar())<'0'||ch>'9') if (ch=='-') f=-1;ans=ch-'0';while ((ch=getchar())>='0'&&ch<='9') ans=ans*10+ch-'0';return ans*f;}int n,m,tot;stack<int> s;struct aa{int lc,rc,size;}a[4000005];int new_node(){int u;if (!s.empty()) u=s.top(),s.pop();else u=++tot;a[u].lc=a[u].rc=a[u].size=0;return u; }void insert(int &u,int l,int r,int val){if (u==0) u=new_node();a[u].size++;if (l==r) return;int mid=(l+r)>>1;if (val<=mid) insert(a[u].lc,l,mid,val);else insert(a[u].rc,mid+1,r,val);}ll cnt0,cnt1;int merge(int u1,int u2,int l,int r){if (u1==0) return u2;if (u2==0) return u1;cnt0+=(ll)a[a[u1].lc].size*a[a[u2].rc].size;//exchangecnt1+=(ll)a[a[u2].lc].size*a[a[u1].rc].size;//not exchangea[u1].size+=a[u2].size;if (l==r) {s.push(u2);return u1;}int mid=(l+r)>>1;a[u1].lc=merge(a[u1].lc,a[u2].lc,l,mid);a[u1].rc=merge(a[u1].rc,a[u2].rc,mid+1,r);s.push(u2);return u1;}pii work(){int x=read();if (x!=0){int tmp=0;insert(tmp,1,n,x);return MK(tmp,0);}pii tmpl=work(),tmpr=work();cnt0=cnt1=0;int rt=merge(tmpl.fi,tmpr.fi,1,n);return MK(rt,min(cnt0,cnt1)+tmpl.se+tmpr.se);}int main(){n=read();pii ans=work();printf("%lld",ans.se);return 0;}


 

0 0
原创粉丝点击