HDU2018多校第五场部分题目

HDU2018多校第五场部分题目

这场4题滚了,傻逼点分治想不到。。

A Always Online(hdu 6350)

题目描述
http://acm.hdu.edu.cn/showproblem.php?pid=6350

题解
开场看了这题,然后没看清楚题目条件,被那个式子吓跑了。
这个题有一个很重要的条件,每条边最多只会属于一个简单环。
我们把最大流转换成最小割,任意两个点之间的最小割肯定在两点路径上某个环上的两条边或一条桥边。
对于每个环,最小的那条边肯定会被割掉。
我们把这张图缩点双,每个大于一条边的点双把最小的边拿出来,对于其他的边,把这条最小边的权值加上去。
剩下的边就变成了一棵树。
从大到小枚举每条边,按位处理处每个联通块的状态,拿个并查集按位合并一下就好了。

代码

#include
#define ll unsigned long long
#define N 200005
#define D 32
using namespace std;
int T,n,m,cnt,q[N],top,dfn[N],low[N],flag[N],p[N],fa[N];
int k,la[N],ff[N*2],tot,blo[N],t[N][D][2],size[N];ll ans;
struct node{
  int a,b,c;
  node operator+(const node &p)const{return (node){a,b,c+p.c};}
  bool operator<(const node &p)const{return c2],s[N];

void add(int a,int b,int c)
{
  e[++k]=(node){a,b,c};ff[k]=la[a];la[a]=k;
  e[++k]=(node){b,a,c};ff[k]=la[b];la[b]=k;
}

void dfs(int x,int pre)
{
  dfn[x]=++cnt;low[x]=cnt;
  for(int a=la[x];a;a=ff[a])
  {
    int ed=(a>>1);
    if(!flag[ed])flag[ed]=1,q[++top]=ed;
    if(!dfn[e[a].b])
    {
      dfs(e[a].b,ed);
      low[x]=min(low[x],low[e[a].b]);
      if(low[e[a].b]>=dfn[x])
      {
        tot++;
        while(top&&q[top]!=ed)blo[q[top]]=tot,top--,size[tot]++;
        blo[ed]=tot;top--;size[tot]++;
      }
    }
    else if(ed!=pre)low[x]=min(low[x],dfn[e[a].b]);
  }
}

int find(int x)
{
  if(fa[x]==x)return x;
  return fa[x]=find(fa[x]);
}


int main()
{
  int a,b,c;
  scanf("%d",&T);
  while(T--)
  {
    k=1;cnt=0;tot=0;ans=0;
    memset(la,0,sizeof(la));
    memset(ff,0,sizeof(ff));
    memset(p,0,sizeof(p));
    memset(t,0,sizeof(t));
    memset(blo,0,sizeof(blo));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(flag,0,sizeof(flag));
    memset(size,0,sizeof(size));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
      scanf("%d%d%d",&a,&b,&c),add(a,b,c);
    for(int i=1;i<=n;i++)if(!dfn[i])dfs(1,0);cnt=0;
    for(int i=1;i<=m;i++)
      if(!p[blo[i]]||e[i<<1].c1].c)p[blo[i]]=i;
    for(int i=1;i<=m;i++)
    {
      if(p[blo[i]]!=i)s[++cnt]=e[i<<1]+e[p[blo[i]]<<1];
      else if(size[blo[i]]==1)s[++cnt]=e[i<<1];
    }
    sort(s+1,s+cnt+1);
    for(int i=1;i<=n;i++)fa[i]=i;
    for(int i=1;i<=n;i++)
      for(int j=0;j<=31;j++)t[i][j][(i>>j)&1]=1;
    for(int i=cnt;i;i--)
    {
      a=s[i].a;b=s[i].b;c=s[i].c;
      a=find(a);b=find(b);fa[b]=a;
      for(int j=0;j<=31;j++)
      {
        if((c>>j)&1)ans+=(1ll<0]*t[b][j][0]+(ll)t[a][j][1]*t[b][j][1]);
        else ans+=(1ll<0]*t[b][j][1]+(ll)t[a][j][1]*t[b][j][0]);
        for(int k=0;k<=1;k++)t[a][j][k]+=t[b][j][k]; 
      }
    }
    printf("%llu\n",ans);
  }
  return 0;
}

D Daylight(hdu 6353)

题目描述

题解
傻逼点分治。。。
如果每次只询问一个点,那就动态点分治,每个分治子树维护一下分治根到每个点的路径长度,每次查询的时候二分一下就就好了。
然后这题有两个点,会有交叉,然后就不会做了。
其实很简单,对于这两个点,求个中点,对于中点求一下距离中点小于len/2的点的数量容斥一下就好了。
为了方便写,把每条边变成一个点,这样可以防止两点距离为偶数找不到中点。
这题卡常数,把lca改成树剖在勉强卡过去。。。

代码

#include
#define inf 2100000000
#define N 200010
#define D 18
#define _(d) while(d((ch=getchar()-48)>=0))
using namespace std;
int T,n,m,dep[N],d[N][D+1],pre[N],ans,tot;
int fa[N],flag[N],q[N],check[N],h[N],f[N],size[N];
int k,la[N],ff[N*2],nxt[N],top[N],pa[N],po[N],pos[N];
vector<int>t1[N],t2[N];
struct node{int a,b;}e[N*2];
inline void add(int a,int b)
{
  e[++k]=(node){a,b};ff[k]=la[a];la[a]=k;
  e[++k]=(node){b,a};ff[k]=la[b];la[b]=k;
}
inline int read()
{
  char ch;_(!);int x=ch;
  _() x=(x<<3)+(x<<1)+ch;return x;
}

void bfs()
{
  int l=1,r=2;q[1]=1;dep[1]=1;tot=0;
  while(lint x=q[l++];size[x]=1;
    for(int a=la[x];a;a=ff[a])
    {
      if(dep[e[a].b])continue;
      q[r]=e[a].b;pa[q[r]]=x;dep[q[r]]=dep[x]+1;r++;
    }
  }
  for(int i=r-1;i;i--)
  {
    int x=q[i];if(!pa[x])continue;
    size[pa[x]]+=size[x];
    if(size[nxt[pa[x]]]x])nxt[pa[x]]=x;
  }
  for(int i=1;iint x=q[i];if(top[x])continue;
    for(int j=x;j;j=nxt[j])top[j]=x,po[pos[j]=++tot]=j;
  }
}

int lca(int a,int b)
{
  while(top[a]!=top[b])
  {
    if(dep[top[a]]if(dep[a]return a;
  return b;
}

inline int find_root(int S)
{
  int l=1,r=2,num=inf,res=0;q[1]=S;flag[S]=1;fa[S]=0;
  while(lint x=q[l++];f[x]=0;size[x]=1;
    for(int a=la[x];a;a=ff[a])
      if(!flag[e[a].b]&&!check[e[a].b])
        q[r]=e[a].b,flag[q[r]]=1,fa[q[r]]=x,++r;
  }
  for(int i=r-1;i;--i)
  {
    int x=q[i],val=max(f[x],r-size[x]-1);flag[x]=0;
    if(fa[x])size[fa[x]]+=size[x],f[fa[x]]=max(f[fa[x]],size[x]);
    if(valx;
  }
  return res;
}

inline void bfs(int S,int dep)
{
  int l=1,r=2;q[1]=S;d[S][dep]=0;flag[S]=1;
  while(lint x=q[l++];
    if(x<=n){
      t1[S].push_back(d[x][dep]);
      t2[S].push_back(d[x][dep-1]);
    }
    for(int a=la[x];a;a=ff[a])
      if(!flag[e[a].b]&&!check[e[a].b])
      {
        q[r]=e[a].b;flag[q[r]]=1;
        d[q[r]][dep]=d[x][dep]+1;++r;
      }
  }
  for(int i=r-1;i;--i)flag[q[i]]=0;
  sort(t1[S].begin(),t1[S].end());
  sort(t2[S].begin(),t2[S].end());
}

inline int cal(const vector<int>&t,int len)
{
  if(!t.size()||t[0]>len)return 0;
  if(t[t.size()-1]<=len)return t.size();
  int pos=upper_bound(t.begin(),t.end(),len)-t.begin();
  return pos;
}

inline int qry(int x,int w)
{
  int res=cal(t1[x],w-d[x][h[x]]);
  for(int i=x;pre[i];i=pre[i])
  {
    res+=cal(t1[pre[i]],w-d[x][h[pre[i]]]);
    res-=cal(t2[i],w-d[x][h[pre[i]]]);
  }
  return res;
} 

int build(int x,int dep)
{
  x=find_root(x);check[x]=1;
  h[x]=dep;bfs(x,dep);
  for(int a=la[x];a;a=ff[a])
    if(!check[e[a].b])pre[build(e[a].b,dep+1)]=x;
  return x;
}

inline int get(int x,int len)
{
  while(len)
  {
    if(pos[x]-pos[top[x]]>=len)return po[pos[x]-len];
    len-=pos[x]-pos[top[x]]+1;x=pa[top[x]];
  }
  return x;
}

inline int find(int a,int b,int &len)
{
  int p=lca(a,b);
  len=dep[a]+dep[b]-dep[p]*2;
  if(dep[a]-dep[p]>=len/2)return get(a,len/2);
  return get(b,len/2);
}

int main()
{
  int a,b,c,p,len;
  T=read();
  while(T--)
  {
    n=read();m=read();
    for(int i=1;i<=k;++i)ff[i]=0;k=0;
    for(int i=1;i<=n*2;++i)
    {
      t1[i].clear();t2[i].clear();
      la[i]=0;check[i]=0;pre[i]=0;dep[i]=0;nxt[i]=0;top[i]=0;
    }
    for(int i=1;iread();b=read();
      add(a,n+i);add(b,n+i);
    }
    bfs();build(1,1);ans=0;
    while(m--)
    {
      a=(read()+ans)%n+1;b=(read()+ans)%n+1;
      c=(read()+ans)%n;p=find(a,b,len);len/=2;
      if(!c)printf("%d\n",ans=(a==b?1:2));
      else printf("%d\n",ans=qry(a,c*2)+qry(b,c*2)-qry(p,c*2-len));
    }
  }
  return 0;
} 

你可能感兴趣的:(题解,数据结构,——树分治,——并查集,套题总结)