Edu10
C:一个n排列,其中有m对数,问有多少个区间满足区间里不含成对的数
对于一对数对应的下标(l,r),若一个区间左端点为l,那么右端点必须<r,否则就含有(l,r)这一对了.遍历一遍后,发现会有[l,r-1]中包含其他pair的情况,就需要从后往前遍历,i位置到达的最远下标不能大于i+1位置到达的最远下标,不然就包含了i+1那一段.
int n,m;
int vis[N]; //i对应下标
int dp[N]; //下标i能到的最远位置
void work() {
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++) {
int v;
scanf("%d",&v);
vis[v]=i;
dp[i] = n+1;
}
while(m--) {
int l,r;
scanf("%d%d",&l,&r);
if(vis[l] > vis[r])swap(l,r);
dp[vis[l]] = min(dp[vis[l]],vis[r]);
}
for(int i=n-1; i>=1; i--) {
dp[i] = min(dp[i],dp[i+1]);
}
ll ans =0;
for(int i=1; i<=n; i++) {
ans += dp[i] - i;
}
printf("%lld
",ans);
}
D.树状数组+离散化
题意:一堆线段,问你每条线段内"包含"了几条其他线段.
将线段按照右端点升序排序,对于线段i和i-1,因为i.r >= (i-1).r,所以若(i-1).l >= i.l,那么i-1线段就在i里面.
同理,对于线段x,只需看1~x-1中有多少左端点 >= x.l.
把左端点用树状数组维护,sum(x.r)-sum(x.l-1)表示包含的左端点个数.(注意开两倍空间....WA了无数次)
const int N = 4e5 + 50;
int n;
int l[N],r[N];
int lsh[N],tot =0;
int c[N];
int lowbit(int n) {
return n & (-n);
}
void update(int x,int y) {
for(; x<=N; x+=lowbit(x))c[x] += y;
}
int sum(int x) {
int ans =0 ;
for(; x; x-=lowbit(x))ans += c[x];
return ans;
}
struct node {
int l,r;
int id;
} p[N];
bool cmp(node a,node b) {
if(a.r != b.r)return a.r < b.r;
return a.l > b.l;
}
int ans[N];
void work() {
scanf("%d",&n);
for(int i=0; i<n; i++) {
scanf("%d%d",&p[i].l,&p[i].r);
if(p[i].l > p[i].r)swap(p[i].r,p[i].l);
p[i].id = i;
lsh[tot++] = p[i].l;
lsh[tot++] = p[i].r;
}
sort(lsh,lsh+tot);
tot = unique(lsh,lsh+tot)-lsh;
sort(p,p+n,cmp);
for(int i=0; i<n; i++) {
int lll = lower_bound(lsh,lsh+tot,p[i].l)-lsh +1;
int rrr = lower_bound(lsh,lsh+tot,p[i].r)-lsh+1;
if(lll > rrr)swap(lll,rrr);
int l1 = sum(lll-1);
int r1 = sum(rrr);
ans[p[i].id] = r1-l1;
update(lll,1);
}
for(int i=0; i<n; i++) {
printf("%d
",ans[i]);
}
}