CF 240F TorCoder(線段樹)
轉載請註明出處,謝謝http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove
題意:給出一個字串,有m次操作,每次給出一個區間,把區間重新調整成一個迴文序列,如果有多種操作,選擇字典序最小的。如果不能操作則不操作。最後輸出最終的字串
剛入手,感覺好神奇的題,其實要自己多思考。想一下,其實還是很簡單的。
首先我們統計一下區間內各個字母的數量,然後比較區間長度的奇偶性,就知道是否 可以操作。
面對於迴文串的字典序最小,顯然是確定,只需要從小到大列舉26個字母就行了。
所以做法是:線段樹統計區間內各個字母的數量
然後根據區間長度的奇偶性,判斷是否可以操作。
如果可以操作,就進行對稱的區間更新。
注意個細節:對於如果是區間長度是奇數的,那麼肯定有且只有一種字母的個數是奇數,那麼肯定這個字母位於中間,然後其它字母還是按照字母順序,兩邊更新。
大概的每次更新的複雜度是大概查詢是26*lgn,然後更新是26*lgn,大概跑了2.5s
#include<iostream>
#include<cstdio>
#include<cstring>
#define mem(a,b) memset(a,b,sizeof(a))
#define N 100005
#define lson step<<1
#define rson step<<1|1
using namespace std;
struct Seg_tree{
int left,right;
int cnt[26],lazy;
}L[N<<2];
int n,m;
char str[N];
int cnt[26];
void push_up(int step){
for(int i=0;i<26;i++)
L[step].cnt[i]=L[lson].cnt[i]+L[rson].cnt[i];
}
void update(int step,int l,int r,int k);
void push_down(int step){
if(L[step].lazy!=-1){
int l=L[step].left,r=L[step].right,m=(l+r)>>1;
update(lson,l,m,L[step].lazy);
update(rson,m+1,r,L[step].lazy);
L[step].lazy=-1;
}
}
void bulid(int step,int l,int r){
L[step].left=l;
L[step].right=r;
L[step].lazy=-1;
mem(L[step].cnt,0);
if(l==r){
L[step].cnt[str[l]-'a']++;
L[step].lazy=str[l]-'a';
return ;
}
int m=(l+r)>>1;
bulid(lson,l,m);
bulid(rson,m+1,r);
push_up(step);
}
void query(int step,int l,int r){
if(L[step].left==l&&L[step].right==r){
for(int i=0;i<26;i++)
cnt[i]+=L[step].cnt[i];
return ;
}
int m=(L[step].left+L[step].right)>>1;
push_down(step);
if(r<=m) query(lson,l,r);
else if(l>m) query(rson,l,r);
else {
query(lson,l,m);
query(rson,m+1,r);
}
}
void update(int step,int l,int r,int k){
if(L[step].left==l&&L[step].right==r){
mem(L[step].cnt,0);
L[step].cnt[k]=r-l+1;
L[step].lazy=k;
return ;
}
push_down(step);
int m=(L[step].left+L[step].right)>>1;
if(r<=m) update(lson,l,r,k);
else if(l>m) update(rson,l,r,k);
else {
update(lson,l,m,k);
update(rson,m+1,r,k);
}
push_up(step);
}
void slove(int step){
if(L[step].left==L[step].right){
putchar(L[step].lazy+'a');
return ;
}
push_down(step);
slove(lson);
slove(rson);
}
int main(){
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
scanf("%d%d%s",&n,&m,str+1);
bulid(1,1,n);
while(m--){
int l,r;
scanf("%d%d",&l,&r);
mem(cnt,0);
query(1,l,r);
if((r-l+1)&1){
int k=0,p;
for(int i=0;i<26;i++)
if(cnt[i]&1) k++,p=i;
if(k==1){
int a=l,b=r;
cnt[p]--;
for(int i=0;i<26;i++){
if(cnt[i]){
update(1,a,a+cnt[i]/2-1,i);
update(1,b-cnt[i]/2+1,b,i);
a+=cnt[i]/2;
b-=cnt[i]/2;
}
}
update(1,a,b,p);
}
}
else{
int k=0;
for(int i=0;i<26;i++)
if(cnt[i]&1){
k=1;
break;
}
if(!k){
int a=l,b=r;
for(int i=0;i<26;i++){
if(cnt[i]){
update(1,a,a+cnt[i]/2-1,i);
update(1,b-cnt[i]/2+1,b,i);
a+=cnt[i]/2;
b-=cnt[i]/2;
}
}
}
}
}
slove(1);putchar('\n');
return 0;
}
相關文章
- CF940E Cashback 線段樹優化DP優化
- CF19D 線段樹+STL各種應用
- CF EDU165-E-序列問題,線段樹
- CF798E. Mike and code of a permutation [拓撲排序 線段樹]排序
- CF580E Kefa and Watch (線段樹維護雜湊)
- 線~段~樹
- 線段樹
- 線段樹最佳化 DP & CF833B The Bakery 題解
- 線段樹 hate it
- 01 線段樹
- 線段樹--RMQMQ
- 李超線段樹
- 線段樹模板
- 【模版】線段樹
- ut.cpp 最大線段並減線段交 [線段樹]
- 線段樹筆記筆記
- 線段樹入門
- 權值線段樹
- 線段樹進階
- 線段樹(毒瘤)總結
- 線段樹模板總結
- 深入理解線段樹
- 線段樹入門理解
- 第二課——線段樹
- 線段樹簡單思路
- 線段樹擴充套件套件
- 線段樹 transformation——hdu 4578ORM
- 線段樹(超詳解)
- 線段樹 - 多組圖帶你從頭到尾徹底理解線段樹
- 資料結構之樹( 線段樹,字典樹)資料結構
- 資料結構-線段樹資料結構
- 關於線段樹基礎
- 淺談線段樹(Segment Tree)
- hdu 1754 I Hate It (線段樹)
- [18/03/24] 線段樹模板
- 動態開點線段樹
- 線段樹入門(Segment Tree)
- 線段樹學習筆記筆記