标签:pre namespace uri tps struct etc 端点 show read
链接:https://www.luogu.org/problemnew/show/P1972
好题
last数组是本题的关键.
last数组是一个链表,链接上一个相同颜色的位置.
考虑如何操作.
用树状数组维护.
树状数组p[i]表示第i个位置的值(值代表这个颜色是否有效)
先把操作离线下来(经典操作)
然后按照右端点排序.
因为是按照右端点排序,所以出现的颜色只关心最右的.
所以要在last[当前颜色] 位置 - 1.然后在这个地方+1
然后查询[l,r]的和即可.
#include <algorithm>
#include <iostream>
#include <cstdio>
#define rep(i,x,p) for(int i = x;i <= p;++ i)
#define lowbit(x) x & -x
#define gc getchar()
#define pc putchar
const int maxN = 5e5 + 7;
int a[maxN];
int last[1000007];
using namespace std;
int p[maxN];
struct Node{
int l,r,id,w;
}Q[maxN];
int n,m;
bool cmp(Node a,Node b) {return a.r < b.r;}
bool cmp1(Node a,Node b){return a.id < b.id;}
inline void add(int x,int w) {
if(!x) return ;
while(x <= n) {p[x] += w;x += lowbit(x);}
}
inline int query(int x) {
int sum = 0;
while(x) {sum += p[x];x -= lowbit(x);}
return sum;
}
inline int read() {
int x = 0,f = 1;char c = gc;
while(c < ‘0‘ || c > ‘9‘) {if(c == ‘-‘)f = -1;c = gc;}
while(c >= ‘0‘ && c <= ‘9‘) {x = x * 10 + c - ‘0‘;c = gc;}
return x * f;
}
void print(int x) {
if(x >= 10) print(x / 10);
pc(x % 10 + ‘0‘);
}
int main() {
n = read();
rep(i , 1, n) a[i] = read();
m = read();
rep(i , 1, m) {
Q[i].l = read();Q[i].r = read();
Q[i].id = i;
}
sort(Q + 1,Q + m + 1,cmp);
rep(i , 1, m) {
int end = Q[i].r;
rep(j , Q[i - 1].r, end) {
if(last[a[j]]) add(last[a[j]],-1);
last[a[j]] = j;add(j,1);
}
Q[i].w = query(Q[i].r) - query(Q[i].l - 1);
}
sort(Q + 1,Q + m + 1,cmp1);
rep(i , 1, m) {
print(Q[i].w);
pc(‘\n‘);
}
return 0;
}
标签:pre namespace uri tps struct etc 端点 show read
原文地址:https://www.cnblogs.com/gzygzy/p/9924693.html