題目大意:每次給一段區間染色,求最後整個區間有多少種顏色;
分析:用膝蓋想也知道這題線段樹可以輕鬆水過,於是出題人靈機一動,挖了個深坑,每次給的區間是左開右閉的,但題目沒說,他給了你一張圖,你們可以感受一下:
於是正解wa成0分我也是很絕望的。有一點要注意一下,離散化後有些區間會並在一起,原來中間的顏色可能會被消掉,於是考慮兩次離散化,先離散化一次,若相鄰兩個點的值不為1,就在中間插乙個點,然後再離散化一次。不過仔細對拍後會發現,在1e9內這種情況太少,除非出題人喪心病狂,否則是不會卡的。第二種做法,o(n),每次考慮倒著染色,然後每次用並差集維護,若維護到一段已經屬於寧外的集合,就跳到這個集合的最右端繼續染。最後盤一下不同集合的個數就ok了,因為n次詢問,所以一共合併n-1次,複雜度不超過o(n)。
線段樹:
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
using namespace std;
int getint()
const int n=2e6+5;
struct node
q[n];
intm,n,ans,b[n<<1];
int tag[n<<3];
bool exist[n];
void lsh()
}void pushdown(int k)
void modify(int k,int l,int r,int
x,int
y,int v)
if(tag[k])pushdown(k);
int mid=l+r>>1;
if(y
<=mid)modify(k<<1,l,mid,x,y,v);
else
if(x>mid)modify(k<<1|1,mid+1,r,x,y,v);
else modify(k<<1,l,mid,x,mid,v),modify(k<<1|1,mid+1,r,mid+1,y,v);
}void solve(int k,int l,int r)
if(tag[k])pushdown(k);
int mid=l+r>>1;
solve(k<<1,l,mid),solve(k<<1|1,mid+1,r);
}int main()
lsh();
for(int i=1;i<=m;i++)
modify(1,1,n,q[i].l,q[i].r,i);
solve(1,1,n);
cout
return
0;}
並差集:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using
namespace
std;
const
int n=4e6+100;
int n,m,tot,cnt,b[n],ans,jump[n],check[n],po,ri[n];
bool flag[n/2];
struct nodea[n/2];
int readint()
for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<3)+(i<<1)+ch-'0';
return i*f;
}inline
int find(int x)
void dis_init()
}int main()
dis_init();
for(int i=n;i>=1;i--)
}
}printf("%d",ans);
return
0;}
離散化 線段樹
題目 分析 每次1操作會往序列底加first個second,first 和 second 都是最大1e9的資料,每次2操作詢問序列中第first到第second個數的和 一開始就感覺有點像線段樹,輸入資料太大我們可以離線處理把資料離散化下,然後扔到線段樹上,維護兩個陣列 sum 區間數的值的和 nu...
資料離散化 線段樹
前言 遇到了乙個矩形面積堆疊的問題,想了很久。終於找到了方法。先做個小記,待到具體問題時再分析。資料離散化 高大上的名字,其實就是對資料的一種處理,也可以採取陣列 或者 容器 map vector。之類的來儲存。之前的ibm技術俱樂部主席競選 那道題其實就是很好的應用。有些資料本身很大,自身無法作為...
線段樹 離散化 染色
這個題目太坑了,一直給報超時,然後調了一下午發現多開了乙個map。ac include include include include include include include includeusing namespace std define maxn 10000000 100 define...