[POI2011] MET-Meteors
前言
现在是2022年,这里是烂大街的 \(O(n\log_2^2n)\) 树状数组+整体二分做法,想学习 \(O(n\log_2n)\) 做法的请移步 jiangly哥哥博客。
题目
讲解
唔,大家应该都会树状数组区间加+单点查吧。
嘛,其实对整体二分熟悉的同学在知道这道题是整体二分之后应该就没什么障碍了。
具体讲一讲,我们对每个国家 \(c\) 可以二分答案然后 \(O(\log_2n\sum[o_i=c])\) 检查,事实上我们所有国家一起做二分就可以保证复杂度了,用一个函数 solve(l,r,ql,qr)
表示国家编号在 \(ID_i(l\le i\le r)\) 的国家的二分区间是 \([ql,qr]\) 即可简单实现。
时间复杂度 \(O(n\log_2^2n)\)。
代码
不精细实现 2.64s
//12252024832524
#include <bits/stdc++.h>
#define TT template<typename T>
using namespace std;
typedef long long LL;
const int MAXN = 300005;
int n,m,k;
int ans[MAXN],pur[MAXN];
LL Read()
{
LL x = 0,f = 1;char c = getchar();
while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
return x * f;
}
TT void Put1(T x)
{
if(x > 9) Put1(x/10);
putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
if(x < 0) putchar('-'),x = -x;
Put1(x); if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x){return x < 0 ? -x : x;}
int head[MAXN],tot;
struct edge{
int v,nxt;
}e[MAXN];
void Add_Edge(int u,int v){
e[++tot] = edge{v,head[u]};
head[u] = tot;
}
struct meteorite{
int l,r,num;
}s[MAXN];
LL B[MAXN];
int lowbit(int x){return x & -x;}
void Add(int x,int val){for(int i = x;i <= m;i += lowbit(i)) B[i] += val;}
LL Sum(int x){LL ret = 0;for(int i = x;i >= 1;i ^= lowbit(i)) ret += B[i];return ret;}
void Add(int l,int r,int val){
if(l <= r){
Add(l,val);
Add(r+1,-val);
}
else{
Add(1,val); Add(r+1,-val);
Add(l,val);
}
}
int ID[MAXN],tmp[MAXN];
void solve(int l,int r,int ql,int qr){
if(ql == qr){
for(int i = l;i <= r;++ i) ans[ID[i]] = ql;
if(ql <= k) Add(s[ql].l,s[ql].r,s[ql].num);
return;
}
int mid = (ql+qr) >> 1,ll = l,rr = r;
for(int i = ql;i <= mid;++ i) Add(s[i].l,s[i].r,s[i].num);
for(int x = l;x <= r;++ x){
LL cur = 0;
for(int i = head[ID[x]]; i && cur < pur[ID[x]];i = e[i].nxt)
cur += Sum(e[i].v);
if(cur >= pur[ID[x]]) tmp[ll++] = ID[x];
else tmp[rr--] = ID[x];
}
for(int i = ql;i <= mid;++ i) Add(s[i].l,s[i].r,-s[i].num);
for(int i = l;i <= r;++ i) ID[i] = tmp[i];
solve(l,ll-1,ql,mid);
solve(rr+1,r,mid+1,qr);
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
n = Read(); m = Read();
for(int i = 1;i <= m;++ i) Add_Edge(Read(),i);
for(int i = 1;i <= n;++ i) pur[i] = Read();
k = Read();
for(int i = 1;i <= k;++ i) s[i].l = Read(),s[i].r = Read(),s[i].num = Read();
for(int i = 1;i <= n;++ i) ID[i] = i;
solve(1,n,1,k+1);
for(int i = 1;i <= n;++ i)
if(ans[i] == k+1) printf("NIE\n");
else Put(ans[i],'\n');
return 0;
}
精细实现 1.89s
//12252024832524
#include <bits/stdc++.h>
#define TT template<typename T>
using namespace std;
typedef long long LL;
const int MAXN = 300005;
int n,m,k;
int ans[MAXN],pur[MAXN];
LL Read()
{
LL x = 0,f = 1;char c = getchar();
while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
return x * f;
}
TT void Put1(T x)
{
if(x > 9) Put1(x/10);
putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
if(x < 0) putchar('-'),x = -x;
Put1(x); if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x){return x < 0 ? -x : x;}
int head[MAXN],tot;
struct edge{
int v,nxt;
}e[MAXN];
void Add_Edge(int u,int v){
e[++tot] = edge{v,head[u]};
head[u] = tot;
}
struct meteorite{
int l,r,num;
}s[MAXN];
LL B[MAXN];
int lowbit(int x){return x & -x;}
void Add(int x,int val){for(int i = x;i <= m;i += lowbit(i)) B[i] += val;}
LL Sum(int x){LL ret = 0;for(int i = x;i >= 1;i ^= lowbit(i)) ret += B[i];return ret;}
void Add(int l,int r,int val){
Add(l,val);
Add(r+1,-val);
if(l > r) Add(1,val);
}
int ID[MAXN],tmp[MAXN];
void solve(int l,int r,int ql,int qr){
if(ql > qr) return;
int mid = (ql+qr) >> 1,ll = l,rr = r;
if(l > r){
for(int i = ql;i <= qr;++ i) Add(s[i].l,s[i].r,s[i].num);
return;
}
for(int i = ql;i <= mid;++ i) Add(s[i].l,s[i].r,s[i].num);
for(int x = l;x <= r;++ x){
LL cur = 0;
for(int i = head[ID[x]]; i && cur < pur[ID[x]];i = e[i].nxt)
cur += Sum(e[i].v);
if(cur >= pur[ID[x]]) ans[ID[x]] = mid,tmp[ll++] = ID[x];
else tmp[rr--] = ID[x];
}
for(int i = ql;i <= mid;++ i) Add(s[i].l,s[i].r,-s[i].num);
for(int i = l;i <= r;++ i) ID[i] = tmp[i];
solve(l,ll-1,ql,mid-1);
Add(s[mid].l,s[mid].r,s[mid].num);
solve(rr+1,r,mid+1,qr);
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
n = Read(); m = Read();
for(int i = 1;i <= m;++ i) Add_Edge(Read(),i);
for(int i = 1;i <= n;++ i) pur[i] = Read();
k = Read();
for(int i = 1;i <= k;++ i) s[i].l = Read(),s[i].r = Read(),s[i].num = Read();
for(int i = 1;i <= n;++ i) ID[i] = i;
solve(1,n,1,k);
for(int i = 1;i <= n;++ i)
if(!ans[i]) printf("NIE\n");
else Put(ans[i],'\n');
return 0;
}