题目描述
输入格式
第一行为数据组数。
对于每一组数据:
输出格式
对于每一组数据:
共N行,第i行输出一个整数,表示第i个团队最早是在哪一轮攻击后就解散,或者-1.
输入样例
1
3 5
1 3 2 1 3
10 5 7
3
4 2 4
1 3 1
3 5 2
输出样例
3
-1
1
题解
这题是整体二分的果题,本来没有什么好讲的,但是蒟蒻我还是打算水一篇博客。。。(因为ACM我们队大半个上午都在码这题,还码不对这题还是有一些值得总结的地方的)
这题与动态区间第K大是有区别的,区别在于修改操作不用放进队列了。这是为什么呢?因为我们二分轮数就可以直接知道该进行哪一段操作了,所以没有放进队列里的必要了?这并不是本质的区别。因为我们动态区间第K大里也可以先将询问排序然后整体二分中再二分找到修改的上下界并完成修改。(很有道理)
你说等等?排序?发现问题了,由于我们要保证询问与修改的相对顺序,所以哪能排序啊!这才是本质的区别。本题题目并没有修改、查询的交替给出,所以并不需要将修改当做操作,放进队列中保证相对顺序地排序,而是直接根据二分出来的轮数进行攻击就可以了。然后套用BIT,其他的跟动态第K大的写法几乎一样。另外就是先用邻接链表记一下每个团队,将每个团队当做一个询问,每次攻击完就扫一遍链表,安置询问位置,这依旧是跟队列长度有关,所以不会退化。对于-1就多加一轮判一下就行了。
那假如修改不在询问之后,直接个体二分行不行呢?当然会超时,这是 O(nKlogm) 的,就是个暴力。
话说这数据有点水,没开long long也能过。。。
代码
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#define N 300010
using namespace std;
int nG, n, m, K;
int head_p[N], cur, BIT[N], ans[N], S[N];
int qL[N], qR[N], q[N];
bool Left[N];
struct Data{
int x, y, C;
}attack[N];
struct Aadj{
int next, obj;
}Edg[N];
void Insert(int a, int b){
cur ++;
Edg[cur].next = head_p[a];
Edg[cur].obj = b;
head_p[a] = cur;
}
int lowbit(int x){
return x & (-x);
}
void Add(int x, int v){
for(int i = x; i <= m; i += lowbit(i)) BIT[i] += v;
}
int Sum(int x){
int res = 0;
for(int i = x; i > 0; i -= lowbit(i)) res += BIT[i];
return res;
}
void Binary(int L, int R, int he, int ta){
if(he > ta) return;
if(L == R){
for(int i = he; i <= ta; i++){
int tmp = q[i];
ans[tmp] = L;
}
return;
}
int mid = (L + R) >> 1;
for(int i = L; i <= mid; i++){
if(attack[i].x <= attack[i].y) Add(attack[i].x, attack[i].C), Add(attack[i].y+1, -attack[i].C);
else Add(attack[i].x, attack[i].C), Add(1, attack[i].C), Add(attack[i].y+1, -attack[i].C);
}
for(int i = he; i <= ta; i++){
int tmp = q[i], res = 0;
for(int j = head_p[tmp]; ~ j; j = Edg[j].next){
int v = Edg[j].obj;
res += Sum(v);
}
if(res >= S[tmp]) Left[i] = true;
else S[tmp] -= res;
}
for(int i = L; i <= mid; i++){
if(attack[i].x <= attack[i].y) Add(attack[i].x, -attack[i].C), Add(attack[i].y+1, attack[i].C);
else Add(attack[i].x, -attack[i].C), Add(1, -attack[i].C), Add(attack[i].y+1, attack[i].C);
}
int cnt1 = 0, cnt2 = 0;
for(int i = he; i <= ta; i++){
int tmp = q[i];
if(Left[i]) qL[++cnt1] = tmp;
else qR[++cnt2] = tmp;
Left[i] = false;
}
for(int i = 1; i <= cnt1; i++) q[he+i-1] = qL[i];
for(int i = 1; i <= cnt2; i++) q[he+cnt1+i-1] = qR[i];
Binary(L, mid, he, he+cnt1-1);
Binary(mid+1, R, he+cnt1, ta);
}
int main(){
freopen("2202.in", "r", stdin);
freopen("2202.out", "w", stdout);
scanf("%d", &nG);
while(nG --){
scanf("%d%d", &n, &m);
cur = -1;
for(int i = 1; i <= n; i++) head_p[i] = -1;
int x;
for(int i = 1; i <= m; i++) scanf("%d", &x), Insert(x, i);
for(int i = 1; i <= n; i++) scanf("%d", &S[i]);
scanf("%d", &K);
for(int i = 1; i <= K; i++)
scanf("%d%d%d", &attack[i].x, &attack[i].y, &attack[i].C);
for(int i = 1; i <= n; i++) q[i] = i;
Binary(1, K+1, 1, n);
for(int i = 1; i <= n; i++){
if(ans[i] == K+1) ans[i] = -1;
printf("%d\n", ans[i]);
}
}
return 0;
}
还会有人让你睡不着
还能为某人燃烧