10 31

  今天考的仍是牛客 牛客的題的質量仍是挺不錯的 至少 我都不會qwq。ios

因爲下一次的沒有參加 因此這裏把下一次的題也順帶說一下。(填坑期間。c++

給人的感受 相似於二分以後模擬。可是模擬的話也就是每次咱們選擇最多的需求開始作 而後這樣 每次都選取最高的那個 而後慢慢填 這樣效率並不高如何快速斷定答案?算法

不知道 實際上是這樣的咱們容易獲得答案的下界max{ai}和 令一個答案的下界 ceil(sum/m) ceil 向上取整的意思。ide

取max咱們獲得了一個答案咱們猜測 一下這個答案是否合法 ?其實花了幾個樣例發現是合法的就能夠寫了 。spa

證實是這樣的咱們依次給每一天分配 第一天分配a1 次日從a1以後繼續分配 而後若是不夠就從頭開始 因爲答案>=max{ai} 3d

這知足了一個限制一天不會被同一個機器作兩次 不可能繞一圈還多 而後發現這樣作就是合法的 而後因爲總次數大於sum因此能夠發現不會出現不夠的狀況 因此咱們成功的構造出來了。code

那就是動態查詢最大值了 multiset便可。值得一提的是我是二分找答案了 爆longlong了。blog

直接除較好。ip

//#include<bits/stdc++.h>
#include<iostream>
#include<queue>
#include<iomanip>
#include<cctype>
#include<cstdio>
#include<deque>
#include<utility>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<cstdlib>
#include<vector>
#include<algorithm>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#define INF 1000000000
#define ll long long
#define db double
#define pb push_back
#define un unsigned
#define mod 1000000007
#define ull unsigned long long
using namespace std;
char *fs,*ft,buf[1<<15];
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline ll read()
{
    ll x=0,f=1;char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
const int MAXN=400010;
ll n,m,q;
ll a[MAXN];
ll sum;
multiset<ll>s;
multiset<ll>::iterator it;
inline ll ask()
{
    ll maxx=*s.rbegin();
    ll w=sum%m==0?sum/m:sum/m+1;
    return max(w,maxx);
}
int main()
{
    //freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);
    n=read();m=read();q=read();
    for(int i=1;i<=n;++i)s.insert(a[i]=read()),sum+=a[i];
    printf("%lld\n",ask());
    for(int i=1;i<=q;++i)
    {
        ll x,y;
        x=read();y=read();
        it=s.find(a[x]);
        s.erase(it);
        sum-=a[x];
        a[x]=y;
        sum+=a[x];
        s.insert(a[x]);
        printf("%lld\n",ask());
    }
    return 0;
}
View Code

算是一道考驗中級難度的圖論題目吧 貪心挺容易看出來的 可是 對仙人掌 仙人掌沙漠 沙漠 迷的同窗就不太友好了。get

仙人掌 一張很是優秀的 圖每條邊最多屬於一個簡單的環 也就是不存在大環套小環的狀況了。

考慮最優性 咱們指望刪除一條邊 最多 能分出一個聯通塊 咱們咱們求出全部的點雙聯通份量也就是環 而後對環進行刪。

而後先把割邊刪掉沒必要要非得求割邊 由於考慮到一個大小爲2的點雙聯通份量中間必定是割邊 因此咱們先刪這個 剩下的從大到小刪便可。

//#include<bits/stdc++.h>
#include<iostream>
#include<queue>
#include<iomanip>
#include<cctype>
#include<cstdio>
#include<deque>
#include<utility>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<cstdlib>
#include<vector>
#include<algorithm>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#define INF 1000000000
#define ll long long
#define db double
#define pb push_back
#define un unsigned
#define mod 1000000007
#define ull unsigned long long
using namespace std;
char *fs,*ft,buf[1<<15];
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
    int x=0,f=1;char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
//滿堂花醉三千客 一劍霜寒十四州.
const int MAXN=1000010;
int n,m,k;
int top,cnt,ans,rt,id,w,len=1;
int q[MAXN];
int s[MAXN];
int dfn[MAXN],low[MAXN],vis[MAXN];
int lin[MAXN],ver[MAXN<<2],nex[MAXN<<2];
inline int cmp(int x,int y){return x>y;}
inline void add(int x,int y)
{
    ver[++len]=y;
    nex[len]=lin[x];
    lin[x]=len;
}
inline void dfs(int x)
{
    dfn[x]=low[x]=++cnt;
    s[++top]=x;
    for(int i=lin[x];i;i=nex[i])
    {
        int tn=ver[i];
        if(!dfn[tn])
        {
            dfs(tn);
            low[x]=min(low[x],low[tn]);
            if(low[tn]==dfn[x])
            {
                int sz=0;
                for(int j;j!=tn;--top)
                {
                    j=s[top];
                    ++sz;
                }
                ++sz;
                if(sz==2){if(k)--k,++ans;}
                else q[++id]=sz;
            }
        }
        else low[x]=min(low[x],dfn[tn]);
    }
}
int main()
{
    //freopen("1.in","r",stdin);
    n=read();m=read();k=read();
    for(int i=1;i<=m;++i)
    {
        int x,y;
        x=read();y=read();
        add(x,y);add(y,x);
    }
    for(int i=1;i<=n;++i)
        if(!dfn[i])
        {
            ++ans;top=0;
            dfs(i);
        }
    sort(q+1,q+1+id,cmp);
    for(int i=1;i<=id;++i)
    {
        if(!k)break;
        --k;
        w=min(k,q[i]-1);
        ans+=w;
        k-=w;
    }
    printf("%d\n",ans);
    return 0;
}
View Code

Ynoi 天降之物可還行qwq. 出毒瘤分塊就沒意思了 話說此題還真的沒意思。

我以爲這道題很屑 因此就不說了。說下暴力/cy 以爲個人暴力很優秀。

這裏強制在線不在線都是沒有用的東西 無聊因爲修改的存在 不存在一些離線的算法。

怎麼求答案?個人想法是考慮歸併的 對位置進行歸併複雜度O(n) 可是這要求有序 把位置放到set裏便可。

因爲這裏是O(n)set因此歸併的複雜度是O(n)的 可是修改的話是nmlog的 很煩對吧。

考慮 一下無修改每次搞完 map存一下答案可大大下降複雜度 近乎應該是O(n~n^2)左右的 能夠跑的很快因此這樣就獲得了50分。

100分作法很屑 毒瘤分塊 而後處理塊內的 和 塊外的 而後 修改的話要整塊打標記碎塊就重構一部分。

整體複雜度 nsqrt(n)+msqrt(n) 。沒寫100分了 我以爲作法很屑。

//#include<bits/stdc++.h>
#include<iostream>
#include<queue>
#include<iomanip>
#include<cctype>
#include<cstdio>
#include<deque>
#include<utility>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<cstdlib>
#include<vector>
#include<algorithm>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#define INF 1000000000
#define ll long long
#define db double
#define pb push_back
#define un unsigned
#define mod 1000000007
#define ull unsigned long long
#define pii pair<int,int>
#define mk(x,y) make_pair(x,y)
using namespace std;
char *fs,*ft,buf[1<<15];
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
    int x=0,f=1;char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
//滿堂花醉三千客 一劍霜寒十四州
//注set均攤 O(n)
const int MAXN=100010;
int n,m,op,flag,last;
struct wy
{
    int op;
    int x,y;
    int z;
}t[MAXN];
int pos[MAXN],w[MAXN];
int a[MAXN],b[MAXN];
set<int>s[MAXN];
set<int>::iterator it,lt;
map<pii,int>H;
inline int ask(int x,int y)
{
    if(x==y)return 0;
    int gg=INF;
    int len1=s[x].size();
    int len2=s[y].size();
    it=s[x].begin();
    lt=s[y].begin();
    int len=len1+len2;
    int i=1,j=len1+1;
    int la=INF,lb=INF;
    for(int k=1;k<=len;++k)
    {
        if(j>len||(i<=len1&&(*it)<(*lt)))
        {
            gg=min(gg,abs(*it-lb));
            la=*it;++it;++i;
            if(j==len+1)break;
        }
        else
        {
            gg=min(gg,abs(*lt-la)),lb=*lt;
            ++lt;++j;
            if(i==len1+1)break;
        }
    }
    return gg;
}
inline void change(int l,int r,int x)
{
    for(int i=l;i<=r;++i)
    {
        if(x==pos[i])continue;
        s[pos[i]].erase(i);
        --w[pos[i]];
        pos[i]=x;
        ++w[pos[i]];
        s[x].insert(i);
    }
}
int main()
{
    //freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);
    n=read();m=read();op=read();
    for(int i=1;i<=n;++i)
    {
        int x;
        x=read();
        pos[i]=x;++w[x];
        s[x].insert(i);
    }
    for(int i=1;i<=m;++i)
    {
        t[i].op=read();
        if(t[i].op==1)
        {
            t[i].x=read();t[i].y=read();t[i].z=read();
            flag=1;
        }
        else
        {
            t[i].x=read();t[i].y=read();
        }
    }
    if(!flag)//無修改操做直接歸併 複雜度 感受很低
    {
        for(int i=1;i<=m;++i)
        {
            int x=t[i].x^last;
            int y=t[i].y^last;
            if(!w[x]||!w[y]){printf("%d\n",-1);last=0;continue;}
            int ans;
            if(H[mk(x,y)])ans=H[mk(x,y)];
            else ans=ask(x,y),H[mk(x,y)]=ans;
            printf("%d\n",ans);
            if(op)last=ans;
        }
        return 0;
    }
    else
    {
        for(int i=1;i<=m;++i)
        {
            if(t[i].op==1)
            {
                change(t[i].x^last,t[i].y^last,t[i].z^last);
            }
            else
            {
                int x=t[i].x^last;
                int y=t[i].y^last;
                if(!w[x]||!w[y]){printf("%d\n",-1);last=0;continue;}
                int ans=ask(x,y);
                printf("%d\n",ans);
                if(op)last=ans;
            }
        }
        return 0;
    }
    return 0;
}
50分
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息