$$ \newcommand{\seq}[2]{{#1}_{1},{#1}_{2},\cdots,{#1}_{#2}} \newcommand{\num}[1]{1,2,\cdots,#1} \newcommand{\stra}[2]{\begin{bmatrix}#1 \\ #2\end{bmatrix}} \newcommand{\strb}[2]{\begin{Bmatrix}#1 \\ #2\end{Bmatrix}} \newcommand{\dw}[1]{\underline{#1}} \newcommand{\up}[1]{\overline{#1}} $$

Codeforces 160

160 D

题意

#define MST 最小生成树

给你一张图
众所周知,一张图的MST不止一个
判断每条边是属于所有的MST,还是属于一部分MST,还是不可能属于任何一个MST
( \(2\le n\le 10^5,n-1\le m\le \min (10^5,\frac{n(n-1)}{2})\) )

Examples

Input
4 5
1 2 101
1 3 100
2 3 2
2 4 2
3 4 1
Output
none
any
at least one
at least one
any
Input
3 3
1 2 1
2 3 1
1 3 2
Output
any
any
none
Input
3 3
1 2 1
2 3 1
1 3 1
Output
at least one
at least one
at least one

使用kruskal算法,先将边排序,然后将边权相同的边放在一起处理
对于一条边,如果边的两个端点在并查集中已经被合并,那么立即放弃,none
将所有没被放弃的边建一张新图,然后跑一遍Tarjan求割边,在所有这些边中,如果一条边是割边,则any,否则at least one
注意,这张图中的点是上一次操作求出的联通块的缩点
然后进行并查集的合并操作
如何求割边(桥)? https://www.cnblogs.com/AireenYe/p/6049061.html

Code

#include<bits/stdc++.h>
#define maxn 200003
#define INF 1050000000
using namespace std;
int n,m,flag[maxn];
namespace MST{
    struct edge{
        int to,next,num;
    }e[maxn];
    int head[maxn],cnte;
    void add(int u,int v,int num){
        e[++cnte].to=v;
        e[cnte].num=num;
        e[cnte].next=head[u];
        head[u]=cnte;
    }
    int low[maxn],dfn[maxn],cntdfn;
    void tarjan(int u,int last){
        low[u]=dfn[u]=++cntdfn;
        for(int i=head[u];~i;i=e[i].next){
            int v=e[i].to;
            if(e[i].num==last)continue;
            if(!dfn[v]){
                tarjan(v,e[i].num);
                low[u]=min(low[u],low[v]);
                if(low[v]>dfn[u])flag[e[i].num]=2;
            }
            else{
                low[u]=min(low[u],dfn[v]);
            }
        }
    }
}
struct edge{
    int from,to,w,num;
    bool operator <(const edge& x)const{
        return w<x.w;
    }
}e[maxn];
int cnte;
void add(int u,int v,int w,int num){
    e[++cnte].from=u;
    e[cnte].to=v;
    e[cnte].w=w;
    e[cnte].num=num;
}
int fa[maxn];
void init(int n){
    for(int i=1;i<=n;i++)fa[i]=i;
}
int find(int x){
    if(x!=fa[x])fa[x]=find(fa[x]);
    return fa[x];
}
void kruskal(){
    sort(e+1,e+cnte+1);
    init(n);
    int i,j;
    for(i=1;i<=cnte;i=j+1){
        for(j=i;e[j].w==e[i].w&&j<=cnte;j++);j--;
        for(int k=i;k<=j;k++){
            int u=find(e[k].from),v=find(e[k].to);
            if(u!=v){
                MST::head[u]=MST::head[v]=-1,MST::low[u]=MST::low[v]=MST::dfn[u]=MST::dfn[v]=0;
            }
        }
        MST::cnte=-1,MST::cntdfn=0;
        for(int k=i;k<=j;k++){
            int u=find(e[k].from),v=find(e[k].to);
            if(u!=v){
                MST::add(u,v,e[k].num),MST::add(v,u,e[k].num);
                flag[e[k].num]=1;
            }
        }
        for(int k=i;k<=j;k++){
            int u=find(e[k].from),v=find(e[k].to);
            if(u!=v){
                if(!MST::dfn[u])MST::tarjan(u,-1);
            }
        }
        for(int k=i;k<=j;k++){
            int u=find(e[k].from),v=find(e[k].to);
            if(u!=v){
                fa[u]=v;
            }
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w,i);
    }
    kruskal();
    for(int i=1;i<=m;i++){
        printf("%s\n",flag[i]==0?"none":(flag[i]==1?"at least one":"any"));
    }
    return 0;
}

160 E

题意

\(n\) 辆公交车, \(m\) 个人
公交车有三个属性:\(s,f,t\) (在 \(t\) 时刻从 \(s\)\(t\)
人也有三个属性:\(l,r,b\) (在 \(b\) 时刻从 \(l\)\(r\)
一个人能上一辆公交车的条件:\(s\le l,r\le f,b\le t\)
现在,每个人要从 \(l\) 赶到 \(r\) ,只能坐一辆公交车,而且要搭乘最早的一辆
求出每个人将会搭乘哪一辆公交车,如果没有符合条件的公交车,输出 \(-1\)
没有两辆公交车的 \(t\) 相同
( n,m\le 10^5,s,f,t,l,r,b\le 10^9 )

Examples

Input
4 3
1 10 10
5 6 2
6 7 3
5 7 4
5 7 1
1 2 1
1 10 11
Output
4 1 -1
Input
1 1
1 1000000000 1000000000
1 1000000000 1000000000
Output
1

先把 \(t,b\) 离散化
把公交车和人放在同一个序列中
然后以左端点为第一条件,右端点为第二条件对该序列排序
以时间为区间建一棵线段树,单点修改
叶节点存公交车的右端点、编号
非叶节点存该区间内最右边的右端点
pushup:当前节点的右端点为两个子节点中右端点的max
insert:修改节点 hash(t) 的右端点、编号
query:如果左儿子区间有答案就返回左儿子的答案,否则返回右儿子的答案

Code

#include<bits/stdc++.h>
#define maxn 400003
#define INF 1050000000
#define ha(x) (lower_bound(mp+1,mp+cntmp+1,(x))-mp)
using namespace std;
struct T{
    int l,r,ti,num;
    bool operator <(const T& x)const{
        return l==x.l?num<x.num:l<x.l;
    }
}a[maxn];
int n,m,cntmp,mp[maxn],ans[maxn];
struct node{
    int rig,num;
    node():rig(-1),num(-1){}
}t[maxn<<2];
void pushup(int p){
    t[p].rig=max(t[p<<1].rig,t[p<<1|1].rig);
}
void change(int p,int l,int r,int pos,int k,int num){
    if(l==r){
        t[p].rig=k;
        t[p].num=num;
        return;
    }
    int mid=(l+r)>>1;
    if(pos<=mid)change(p<<1,l,mid,pos,k,num);
    else change(p<<1|1,mid+1,r,pos,k,num);
    pushup(p);
}
int query(int p,int l,int r,int seg_l,int seg_r,int k){
    if(t[p].rig<k)return -1;
    if(l==r)return t[p].num;
    int mid=(l+r)>>1;
    if(seg_l<=mid){
        int tmp=query(p<<1,l,mid,seg_l,seg_r,k);
        if(tmp!=-1)return tmp;
    }
    if(seg_r>mid){
        return query(p<<1|1,mid+1,r,seg_l,seg_r,k);
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n+m;i++){
        scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].ti);
        a[i].num=i;
        mp[++cntmp]=a[i].ti;
    }
    sort(mp+1,mp+cntmp+1);
    cntmp=unique(mp+1,mp+cntmp+1)-mp-1;
    sort(a+1,a+n+m+1);
    for(int i=1;i<=n+m;i++){
        if(a[i].num>n){
            ans[a[i].num-n]=query(1,1,cntmp,ha(a[i].ti),cntmp,a[i].r);
        }
        else{
            change(1,1,cntmp,ha(a[i].ti),a[i].r,a[i].num);
        }
    }
    for(int i=1;i<=m;i++)printf("%d ",ans[i]);
    return 0;
}
posted @ 2019-02-14 15:07  chc_1234567890  阅读(219)  评论(0编辑  收藏  举报