专栏文章
题解:AT_joisc2013_spy スパイ (Spy)
AT_joisc2013_spy题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @min1xoft
- 此快照首次捕获于
- 2025/12/01 19:14 3 个月前
- 此快照最后确认于
- 2025/12/01 19:14 3 个月前
这道题我一直在想怎么用扫描线来做,后面实在是没招了,然后再仔细一看数据范围,发现只要 就可以过了。
进入正题,我们先转换一下题目。对于每个间谍计划输入的 ,,它们以及它们的所有下属都会进行工作,也就是说,在 JOI 社形成的树中,以 为根节点的子树都会被覆盖到;在 IOI 社形成的树中,以 为根节点的子树都会被覆盖到,而对于任意一个点 ,完成任务的条件就是同时被两棵树覆盖到,也就是说这个点要在 的子树里,也要在 的子树里。
那么如何处理这个问题呢?我们可以使用 DFS 序来解决这个问题。
设在深搜时 的进栈时间为 ,以 为根的子树大小为 ,对于 ,若存在节点 ,使得 在这个区间范围之内,则 为 或 的子树中的节点。
设 JOI 社,IOI 社形成的树的 DFS 序分别为 ,,子树大小分别为 , 那么对于查询 完成了多少个任务,就变成了求在输入给出的 个二元组中,有多少个二元组 , 满足:
这个式子长得很像二维偏序,但是我不会打。所以我们重新看一下数据范围,发现 不超过 ,且 的值不会超过 。
于是我们可以再转换一下来求上面那个式子。我们把 这个二元组视作二维平面上的一个点,那么 为横坐标, 为纵坐标,上面那个不等式在平面上就相当于一个矩形,这个矩形以 为左下角,以 为右上角。而我们的目标,也就是求有多少个这样的矩形包含了 这个点。
那么,我们就可以运用二维差分的思想,每次读入一个二元组 和 就把上述矩形部分全部加 ,查询的时候看有多少个矩形覆盖了 这个点即可求出 这个员工完成了多少个任务。
差分部分时间复杂度 ,每个查询 ,总复杂度 可以通过本题。
CPP#include<bits/stdc++.h>
using namespace std;
const int N=2e3+10,M=5e5+10;
int dfn1[N],dfn2[N],num=0,siz1[N],siz2[N];
vector<int> g[N],p[N];
inline void dfs(int u,int fa){
dfn1[u]=++num;
siz1[u]=1;
for(int v:g[u]){
if(v==fa)continue;
dfs(v,u);
siz1[u]+=siz1[v];
}
return;
}
inline void dfs2(int u,int fa){
dfn2[u]=++num;
siz2[u]=1;
for(int v:p[u]){
if(v==fa)continue;
dfs2(v,u);
siz2[u]+=siz2[v];
}
return;
}
int n,m,root1,root2,q;//第一棵树的根节点和第二棵树的根节点
int s[N][N];
inline void update(int x,int y,int a,int b){//将以(x,y)为左下角,(a,b)为右上角的矩形全部加1
s[x][y]+=1;
s[x][b+1]-=1;
s[a+1][y]-=1;
s[a+1][b+1]+=1;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>m;
for(int i=1,x,y;i<=n;i++){
cin>>x>>y;
if(x!=0)g[x].push_back(i),g[i].push_back(x);
else root1=i;
if(y!=0)p[y].push_back(i),p[i].push_back(y);
else root2=i;
}
dfs(root1,0);
num=0;dfs2(root2,0);
//for(int i=1;i<=n;i++)cout<<"dfn1["<<i<<"]="<<dfn1[i]<<" ";cout<<"\n"; for(int i=1;i<=n;i++)cout<<"dfn2["<<i<<"]="<<dfn2[i]<<" ";cout<<"\n";
for(int i=1,x,y;i<=m;i++){
cin>>x>>y;
update(dfn1[x],dfn2[y],dfn1[x]+siz1[x]-1,dfn2[y]+siz2[y]-1);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
//cout<<s[i][j]<<" ";
}
//cout<<"\n";
}
for(int i=1;i<=n;i++)cout<<s[dfn1[i]][dfn2[i]]<<"\n";
return 芙芙天下第一!;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...