本来这几天单挑ccpc camp div2很爽,直到今天遇到了计算几何..............
A.Cactus Draw
签到题
#include
#define ll long long
using namespace std;
const int maxn=1005;
vectorG[maxn];
struct node
{
int x,y;
}ans[maxn];
int vis[maxn],dep[maxn];
void dfs(int u,int fa,int x,int y)
{
ans[u].x=x,ans[u].y=y;
vis[u]=0;
int cnt=0;
for(int i=0;i>n>>m;
for(int i=1;i<=m;i++)
{
cin>>u>>v;
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1,0,1,1);
for(int i=1;i<=n;i++)
printf("%d %d\n",ans[i].x,ans[i].y);
}
C.Division
签到题,优先队列就好了,手残写了线段树
#include
#define ll long long
using namespace std;
const int maxn=1e5+5;
ll mx[maxn*4],sum[maxn*4];
void pushup(int o,int ls,int rs)
{
mx[o]=max(mx[ls],mx[rs]);
sum[o]=sum[ls]+sum[rs];
}
void build(int o,int l,int r)
{
if(l==r)
{
scanf("%lld",&mx[o]);
sum[o]=mx[o];
return;
}
int m=(l+r)/2,ls=o*2,rs=o*2+1;
build(ls,l,m);
build(rs,m+1,r);
pushup(o,ls,rs);
}
void up(int o,int l,int r)
{
if(l==r)
{
mx[o]=sum[o]=mx[o]/2;
return;
}
int m=(l+r)/2,ls=o*2,rs=o*2+1;
if(mx[ls]>=mx[rs])up(ls,l,m);
else up(rs,m+1,r);
pushup(o,ls,rs);
}
int main()
{
int n,k;
scanf("%d%d",&n,&k);
build(1,1,n);
for(int i=1;i<=k;i++)
{
up(1,1,n);
if(mx[1]==0)break;
}
printf("%lld\n",sum[1]);
}
F.Kropki
设d[i][s][j] 是在第 i 个位置时,集合为s,结尾元素是 j 的方案数,我们由第 i 个位置推第 i+1 个位置,我们枚举第 i+1 个位置的元素 p,再枚举 j,如果p 和 j 的取值合法,那么d[ i+1 ][ s|(1< H.Nested Tree 我们先把所有的树都连接起来(1e6个点),然后我们树形dp一下,假设1为根,我们从u走到了v,边u->v的贡献是多少呢?设d[ i ]为以 i 为根的子树的所有节点个数,那么u那边一共有nm-d[v]个点,v这边一共有d[v]个点,显然边u->v的贡献是(nm-d[v])*d[v]。 I.Sorting 被计算几何卡的我时间全用完,看了题解发现这题好简单,由于不能补题,先不写这题,等开放补题再来写。 update:赛后1a了这个题,我们发现不管是执行操作2还是操作3,比不大于x的数相对位置不变,大于x的数也是一样,那么我们把所有不大于x的数看做0,大于x的数看做1,并分别求出这两类数前缀和,把01插入到线段树,操作:2 l r,我就把区间 l r的所有的1移到区间右边去,操作:3 l r,我就把区间 l r 所有的1移到区间左边去,怎么查询 L R 区间和?。我们先找到区间[ 1 , R ]的1个数y,找到区间[ 1 , L-1 ] 的1的个数x,用大于x那类数的前缀和sum[y]-sum[x]就求出来区间[ L , R ]大于x的所有数之和了,不大于x的区间和同理。 #include
#include
#include