Comet OJ - Contest #14
做法
這題是一個很騷的做法。
因爲每次是把整個區間覆蓋爲某個數字,所以可以看作是把一段區間內的很多段數字合併成一個的過程。
我們考慮用去維護這個過程,裏面保存四元組,表示區間都是且是在第個操作之後改變的。以爲關鍵字排序。同時,用一個樹狀數組表示執行了前個操作之後的所有數字總和,每次維護每個操作之後總和的變化。
顯然,在一開始的時候,整個裏面只有,即全部是0。對於一個操作,首先找到包含的那個區間,假設爲,把它分爲和兩個區間,對也做相同的操作。這樣做了之後,就會出現以爲左端點的區間和以爲右端點的區間,這樣接下來我們就可以確定內這兩個區間之間的所有區間。而這些區間就是我們需要去掉的,直接遍歷一遍,在樹狀數組裏面把每個區間對應的及其之後的所有總和減去。最後,再把當前區間對應的四元組加入,對應的在樹狀數組的及其之後都加上相應的和即可。
接下來我們來考慮一下複雜度。對於每個操作,我們最多會拆分左右兩個區間,對應增加兩個四元組,總共就是個四元組。而對於每個四元組,我們最多會在中插入和刪除一次,每次插入和刪除的複雜度是,這裏的複雜度就是。然後,每個操作,我們會在set裏面找其左右端點對應的位置,這裏每次也是的,總時間複雜度不會邊。最後就是樹狀數組的修改,對應每個四元組最多兩次修改,因此整個過程下來複雜度還是。
代碼
#include<bits/stdc++.h>
#define fi first
#define se second
#define LL long long
#define pb push_back
#define lb lower_bound
#define INF 0x3f3f3f3f
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
const int N=1000010;
struct Operation
{
int l,r,x,id;
bool operator < (const Operation &a) const
{
return a.r>r;
}
} op[N];
struct query{int l,r,id;} q[N];
set<Operation> st;
LL c[N],ans[N];
int n,m,Q;
inline void update(int x,LL y)
{
if (x==0) return;
for(int i=x;i<N;i+=i&-i)
c[i]+=y;
}
inline LL getsum(int x)
{
LL res=0;
for(int i=x;i;i-=i&-i)
res+=c[i];
return res;
}
inline bool cmp(query a,query b)
{
return a.r<b.r;
}
inline void split(set<Operation>::iterator it,int x)
{
if (x<it->l||x>it->r) return;
int l=it->l,r=it->r;
int v=it->x,id=it->id;
st.erase(it);
st.insert({l,x,v,id});
st.insert({x+1,r,v,id});
}
int main()
{
sccc(n,m,Q);
for(int i=1;i<=n;i++)
sccc(op[i].l,op[i].r,op[i].x);
for(int i=1;i<=Q;i++)
{
scc(q[i].l,q[i].r);
q[i].id=i;
}
st.insert({1,m,0,0});
sort(q+1,q+1+Q,cmp);
for(int i=1;i<=Q;i++)
{
for(int j=q[i-1].r+1;j<=q[i].r;j++)
{
int l=op[j].l,r=op[j].r,x=op[j].x;
auto L=st.lb({0,l-1,0,0});
split(L,l-1);
auto R=st.lb({0,r,0,0});
split(R,r);
L=st.lb({0,l,0,0});
R=st.lb({0,r+1,0,0});
while(L!=R)
{
auto cur=L; L++;
update(cur->id,(LL)-(cur->r-cur->l+1)*cur->x);
st.erase(cur);
}
update(j,(LL)(r-l+1)*x);
st.insert({l,r,x,j});
}
ans[q[i].id]=getsum(q[i].r)-getsum(q[i].l-1);
}
for(int i=1;i<=Q;i++)
printf("%lld\n",ans[i]);
return 0;
}