模板題。php
簡單題調不過最好的方法是重構代碼或者放一自然後重構代碼。node
1 //Achen 2 #include<algorithm> 3 #include<iostream> 4 #include<cstring> 5 #include<cstdlib> 6 #include<vector> 7 #include<cstdio> 8 #include<queue> 9 #include<cmath> 10 #include<set> 11 #include<map> 12 #define For(i,a,b) for(int i=(a);i<=(b);i++) 13 #define Rep(i,a,b) for(int i=(a);i>=(b);i--) 14 const int N=100007; 15 typedef long long LL; 16 typedef double db; 17 using namespace std; 18 int n,m,SZ,xx[N],yy[N],zz[N],ls[N]; 19 20 template<typename T> void read(T &x) { 21 char ch=getchar(); x=0; T f=1; 22 while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar(); 23 if(ch=='-') f=-1,ch=getchar(); 24 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f; 25 } 26 27 int ecnt,fir[N],nxt[N<<1],to[N<<1]; 28 void add(int u,int v) { 29 nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; 30 nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u; 31 } 32 33 int f[N][20],R[N]; 34 void dfs(int x,int fa) { 35 f[x][0]=fa; 36 R[x]=R[fa]+1; 37 For(i,1,19) f[x][i]=f[f[x][i-1]][i-1]; 38 for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa) 39 dfs(to[i],x); 40 } 41 42 int lca(int x,int y) { 43 if(R[x]<R[y]) swap(x,y); 44 Rep(i,19,0) if(R[f[x][i]]>=R[y]) 45 x=f[x][i]; 46 if(x==y) return x; 47 Rep(i,19,0) if(f[x][i]!=f[y][i]) 48 x=f[x][i],y=f[y][i]; 49 return f[x][0]; 50 } 51 52 vector<int>vc[N]; 53 int tot,ch[N*50][2],rt[N],id[N*50]; 54 LL sg[N*50]; 55 #define lc ch[x][0] 56 #define rc ch[x][1] 57 #define mid ((l+r)>>1) 58 void update(int x) { 59 if(sg[lc]>=sg[rc]) sg[x]=sg[lc],id[x]=id[lc]; 60 else sg[x]=sg[rc],id[x]=id[rc]; 61 } 62 63 void add(int &x,int l,int r,int pos,int v) { 64 if(!x) x=++tot; 65 if(l==r) { sg[x]+=v; id[x]=l; return; } 66 if(pos<=mid) add(lc,l,mid,pos,v); 67 else add(rc,mid+1,r,pos,v); 68 update(x); 69 } 70 71 void merge(int &x,int y,int l,int r) { 72 if(!(x*y)) { x=(x^y); return; } 73 if(l==r) sg[x]=sg[x]+sg[y]; 74 else { 75 merge(lc,ch[y][0],l,mid); 76 merge(rc,ch[y][1],mid+1,r); 77 update(x); 78 } 79 } 80 81 int ans[N]; 82 void dfs2(int x,int fa) { 83 for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa) { 84 dfs2(to[i],x); 85 merge(rt[x],rt[to[i]],1,SZ); 86 } 87 int up=vc[x].size(); 88 For(i,0,up-1) { 89 int w=vc[x][i]; 90 add(rt[x],1,SZ,abs(w),w>0?1:-1); 91 } 92 ans[x]=id[rt[x]]; 93 } 94 95 //#define DEBUG 96 int main() { 97 #ifdef DEBUG 98 freopen("1.in","r",stdin); 99 //freopen(".out","w",stdout); 100 #endif 101 read(n); read(m); 102 For(i,1,n-1) { 103 int x,y; 104 read(x); read(y); 105 add(x,y); 106 } 107 For(i,1,m) { 108 read(xx[i]); read(yy[i]); read(zz[i]); 109 ls[i]=zz[i]; 110 } 111 dfs(1,0); 112 sort(ls+1,ls+m+1); 113 SZ=unique(ls+1,ls+m+1)-(ls+1); 114 For(i,1,m) zz[i]=lower_bound(ls+1,ls+SZ+1,zz[i])-ls; 115 For(i,1,m) { 116 int x=xx[i],y=yy[i],w=zz[i]; 117 int z=lca(x,y); 118 vc[x].push_back(w); 119 vc[y].push_back(w); 120 vc[z].push_back(-w); 121 vc[f[z][0]].push_back(-w); 122 } 123 dfs2(1,0); 124 For(i,1,n) printf("%d\n",ls[ans[i]]); 125 return 0; 126 }
模板題。或許能夠set+啓發式合併水過去。
ios
線段樹合併,合併的時候能夠算出兩種方式的逆序對數,取小的便可。數組
1 //Achen 2 #include<algorithm> 3 #include<iostream> 4 #include<cstring> 5 #include<cstdlib> 6 #include<vector> 7 #include<cstdio> 8 #include<queue> 9 #include<cmath> 10 #include<set> 11 #include<map> 12 #define For(i,a,b) for(int i=(a);i<=(b);i++) 13 #define Rep(i,a,b) for(int i=(a);i>=(b);i--) 14 const int N=400007; 15 typedef long long LL; 16 typedef double db; 17 using namespace std; 18 int n; 19 20 template<typename T> void read(T &x) { 21 char ch=getchar(); x=0; T f=1; 22 while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar(); 23 if(ch=='-') f=-1,ch=getchar(); 24 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f; 25 } 26 27 int tot,ch[N*20][2],rt[N],sg[N*20],leaf; 28 #define lc ch[x][0] 29 #define rc ch[x][1] 30 #define mid ((l+r)>>1) 31 void update(int x) { sg[x]=sg[lc]+sg[rc]; } 32 33 void add(int &x,int l,int r,int pos,int v) { 34 if(!x) x=++tot; 35 if(l==r) { sg[x]+=v; return; } 36 if(pos<=mid) add(lc,l,mid,pos,v); 37 else add(rc,mid+1,r,pos,v); 38 update(x); 39 } 40 41 LL lans,rans; 42 void merge(int &x,int y,int l,int r) { 43 if(!(x*y)) { x=(x^y); return; } 44 if(l==r) sg[x]=sg[x]+sg[y]; 45 else { 46 lans=lans+(LL)sg[rc]*sg[ch[y][0]]; 47 rans=rans+(LL)sg[ch[y][1]]*sg[lc]; 48 merge(lc,ch[y][0],l,mid); 49 merge(rc,ch[y][1],mid+1,r); 50 update(x); 51 } 52 } 53 54 int id,lson[N],rson[N],v[N],RT; 55 int read_a_tree() { 56 int x=++id; read(v[x]); 57 if(v[x]==0) { 58 lson[x]=read_a_tree(); 59 rson[x]=read_a_tree(); 60 } 61 else leaf++; 62 return x; 63 } 64 65 LL ans; 66 void dfs(int x) { 67 if(v[x]) add(rt[x],1,leaf,v[x],1); 68 else { 69 dfs(lson[x]); 70 dfs(rson[x]); 71 lans=rans=0; 72 merge(rt[lson[x]],rt[rson[x]],1,leaf); 73 rt[x]=rt[lson[x]]; 74 ans+=min(lans,rans); 75 } 76 } 77 78 //#define DEBUG 79 int main() { 80 #ifdef DEBUG 81 freopen("1.in","r",stdin); 82 //freopen(".out","w",stdout); 83 #endif 84 read(n); 85 RT=read_a_tree(); 86 dfs(RT); 87 printf("%lld\n",ans); 88 return 0; 89 }
一種比較好寫的作法是,二分答案,把小於它的設爲-1,大於它的設爲1,再用線段樹搞。複雜度是兩個log的,能夠過掉這道題。ide
另外一種複雜度更優秀,適用範圍更廣的作法是線段樹分裂合併。函數
區間排序,把區間左右超過範圍的部分分裂出去,一段區間合併便可。ui
具體來講,另開一棵不用動態開點的線段樹存每一個點所在線段樹維護區間的左右端點,再用數組存每一個左端點對應的右端點,每棵線段樹的根節點掛在左端點上,升序降序的標記也打在左端點上。spa
這樣的時間複雜度能夠證實是nlogn的。code
感謝uoj用戶羣的大佬的證實:blog
勢能分析。勢能函數爲總結點個數。初始節點數nlogn,因爲操做增長的節點數qlogn,合併時額外x的時間花費必定會同時刪去x個節點,因此總時間花費不超過(n+q)logn
感謝Cai大佬爲我這樣無比智障的蒟蒻的解釋:
就是你最開始線段樹上是nlogn個節點,加上每次分裂獲得的qlogn個節點,因此節點總數不會超過(n+q)logn,每次線段樹合併所須要花費的代價就是兩個課都有的公共節點部分,合併完以後這些節點就沒了(在新樹上就是一個節點),而你總共只有(n+q)logn個節點,因此時間複雜度爲(n+q)logn
1 //Achen 2 #include<algorithm> 3 #include<iostream> 4 #include<cstring> 5 #include<cstdlib> 6 #include<vector> 7 #include<cstdio> 8 #include<queue> 9 #include<cmath> 10 #include<set> 11 #include<map> 12 #define For(i,a,b) for(int i=(a);i<=(b);i++) 13 #define Rep(i,a,b) for(int i=(a);i>=(b);i--) 14 const int N=1e5+7; 15 typedef long long LL; 16 typedef double db; 17 using namespace std; 18 int n,m,rt[N],lz[N<<2],flip[N],nx[N]; 19 20 template<typename T> void read(T &x) { 21 char ch=getchar(); x=0; T f=1; 22 while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar(); 23 if(ch=='-') f=-1,ch=getchar(); 24 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f; 25 } 26 27 struct node { int l,r; } sg[N<<2]; 28 #define ls x<<1 29 #define rs ((x<<1)|1) 30 #define mid ((l+r)>>1) 31 void build(int x,int l,int r) { 32 if(l==r) { sg[x].l=l; sg[x].r=r; return; } 33 build(ls,l,mid); build(rs,mid+1,r); 34 } 35 36 void down(int x,int l,int r) { 37 if(!lz[x]||l==r) return; 38 sg[ls].l=sg[x].l,sg[ls].r=sg[x].r; 39 sg[rs].l=sg[x].l,sg[rs].r=sg[x].r; 40 lz[x]=0; lz[ls]=lz[rs]=1; return; 41 } 42 43 void change(int x,int l,int r,int ql,int qr,int ll,int rr) { 44 if(l>=ql&&r<=qr) { 45 sg[x].l=ll; sg[x].r=rr; lz[x]=1; return; 46 } 47 down(x,l,r); 48 if(ql<=mid) change(ls,l,mid,ql,qr,ll,rr); 49 if(qr>mid) change(rs,mid+1,r,ql,qr,ll,rr); 50 } 51 52 node qry(int x,int l,int r,int pos) { 53 if(l==r) return sg[x]; 54 down(x,l,r); 55 if(pos<=mid) return qry(ls,l,mid,pos); 56 else return qry(rs,mid+1,r,pos); 57 } 58 59 int tot,ch[N*50][2],sum[N*50]; 60 #define lc ch[x][0] 61 #define rc ch[x][1] 62 void upd(int x) { sum[x]=sum[lc]+sum[rc]; } 63 64 void update(int &x,int l,int r,int pos,int v) { 65 if(!x) x=++tot; 66 if(l==r) { sum[x]+=v; return; } 67 if(pos<=mid) update(lc,l,mid,pos,v); 68 else update(rc,mid+1,r,pos,v); 69 upd(x); 70 } 71 72 void merge(int &x,int y,int l,int r) { 73 if(!(x*y)) { x=(x^y); return; } 74 if(l==r) { sum[x]+=sum[y]; return; } 75 merge(lc,ch[y][0],l,mid); 76 merge(rc,ch[y][1],mid+1,r); 77 upd(x); 78 } 79 80 node split(int x,int l,int r,int k) { 81 int z=++tot; 82 if(sum[lc]==k) { 83 ch[z][0]=lc; lc=0; 84 } 85 else if(sum[lc]<k) { 86 node tp=split(rc,mid+1,r,k-sum[lc]); 87 ch[x][1]=tp.l; ch[z][1]=tp.r; swap(x,z); 88 } 89 else { 90 node tp=split(lc,l,mid,k); 91 ch[x][0]=tp.r; ch[z][0]=tp.l; 92 } 93 upd(x); upd(z); 94 return (node){z,x}; 95 } 96 97 int find(int x,int l,int r,int pos) { 98 if(l==r) return l; 99 if(sum[lc]>=pos) return find(lc,l,mid,pos); 100 if(sum[lc]<pos) return find(rc,mid+1,r,pos-sum[lc]); 101 } 102 103 //#define DEBUG 104 int main() { 105 #ifdef DEBUG 106 freopen("std.in","r",stdin); 107 //freopen(".out","w",stdout); 108 #endif 109 read(n); read(m); 110 For(i,1,n) nx[i]=i,rt[i]=++tot; 111 build(1,1,n); 112 For(i,1,n) { 113 int x; read(x); 114 update(rt[i],1,n,x,1); 115 } 116 For(i,1,m) { 117 int l,r,o,x; 118 read(o); read(l); read(r); 119 node tl=qry(1,1,n,l); 120 //zhu yi qu fen tp.l tp.r he tl.l tl.r 121 if(tl.l<l) { 122 x=rt[tl.l]; 123 if(flip[tl.l]) { 124 node tp=split(x,1,n,tl.r-tl.l+1-(l-tl.l)); 125 rt[tl.l]=tp.r; rt[l]=tp.l; 126 flip[tl.l]=flip[l]=1; 127 } 128 else { 129 node tp=split(x,1,n,l-tl.l); 130 rt[tl.l]=tp.l; rt[l]=tp.r; 131 flip[tl.l]=flip[l]=0; //zheng biao ji ye yao xia fang 132 } 133 nx[l]=nx[tl.l]; nx[tl.l]=l-1; 134 change(1,1,n,l,nx[l],l,nx[l]); //fen lie hou ye yao xiu gai zhe ke xian duan shu 135 change(1,1,n,tl.l,nx[tl.l],tl.l,nx[tl.l]); 136 } 137 node tr=qry(1,1,n,r); 138 if(tr.r>r) { 139 x=rt[tr.l]; 140 if(flip[tr.l]) { 141 node tp=split(x,1,n,tr.r-r); 142 rt[tr.l]=tp.r; rt[r+1]=tp.l; 143 flip[tr.l]=flip[r+1]=1; 144 } 145 else { 146 node tp=split(x,1,n,(tr.r-tr.l+1)-(tr.r-r)); 147 rt[tr.l]=tp.l; rt[r+1]=tp.r; 148 flip[tr.l]=flip[r+1]=0; 149 } 150 nx[r+1]=nx[tr.l]; nx[tr.l]=r; 151 change(1,1,n,r+1,nx[r+1],r+1,nx[r+1]); 152 change(1,1,n,tr.l,nx[tr.l],tr.l,nx[tr.l]); 153 } 154 change(1,1,n,l,r,l,r); 155 x=l; 156 while(nx[x]+1<=r) { 157 merge(rt[l],rt[nx[x]+1],1,n); 158 if(x==n) break; x=nx[x]+1; 159 } 160 nx[l]=r; 161 flip[l]=o; 162 } 163 int q; read(q); 164 node tp=qry(1,1,n,q); 165 int ans; 166 if(flip[tp.l]) ans=find(rt[tp.l],1,n,tp.r-tp.l+1-(q-tp.l)); 167 else ans=find(rt[tp.l],1,n,q-tp.l+1); 168 printf("%d\n",ans); 169 return 0; 170 }