三分

題:

bzoj3330
bzoj3203YES
bzoj3533YES
bzoj3874
bzoj1857YES
bzoj1229YES

bzoj3533☆

題意:

維護一個向量集合,在線支持以下操作:
"Axy(|x||y|108)" :加入向量(x,y);
"Qxylr(|x||y|1081LRT ,其中T爲已經加入的向量個數)詢問第L個到第R個加入的向量與向量(x,y)的點積的最大值。
集合初始時爲空。

分析:

設詢問點爲(x,y) ,對應答案最大的點爲(x0,y0)
首先(x0,y0) 一定在區間[l,r] 區間中所有點的凸包上。且
y0(x0,y0) 在上凸殼上
y<0(x0,y0) 在下凸殼上
那麼用線段樹維護一下區間,但假如每次插入都更新凸包的話時間就爆炸了。發現如果區間右端點還沒插入時這整段區間是不會查詢的。於是乎只有插入區間右端點是才更新整個區間的上下凸殼。嗯~時間複雜度就是O(nlog2n) 了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>

using namespace std;
typedef long long LL;
const LL inf=21333333333333333;
const int N=1048576;
int n,m,x,y,l,r,v[N],size;
long long lastans,ans;
struct node{int x,y,l,r,op;}g[N];
char s[N],tt[N];
struct point{
    LL x,y;
    point(){}
    point(int _x,int _y):x(_x),y(_y){}
    friend point operator - (point a,point b){
        return point(a.x-b.x,a.y-b.y);
    }
    friend point operator + (point a,point b){
        return point(a.x+b.x,a.y+b.y);
    }
    friend LL operator * (point a,point b){
        return a.x*b.y-a.y*b.x;
    }
    friend LL operator ^ (point a,point b){
        return a.x*b.x+a.y*b.y;
    }
    friend bool operator < (point a,point b){
        if (a.x==b.x)
            return a.y<b.y;
        return a.x<b.x;
    }
}p[N],t[N];

struct range{
    point *up,*dw;
    int ut,dt;
    void gao(int l,int r){
        up=new point[r-l+2];
        dw=new point[r-l+2];
        int top=0;ut=dt=0;
        for (int i=l;i<=r;i++)
            t[++top]=p[i];
        sort(t+1,t+top+1);
        for (int i=1;i<=top;i++){
            while (ut>1 && (t[i]-up[ut])*(up[ut]-up[ut-1])<=0) ut--;
            up[++ut]=t[i];
            while (dt>1 && (dw[dt]-dw[dt-1])*(t[i]-dw[dt])<=0) dt--;
            dw[++dt]=t[i];
        }
    }
    LL query(point k){
        LL res=-inf;
        if (k.y>=0){
            int l=1,r=ut;
            while (r-l>2){
                int ll=l+(r-l)/3;
                int rr=r-(r-l)/3;
                if ((up[ll]^k)<(up[rr]^k))
                    l=ll; else r=rr;
            }
            for (int i=l;i<=r;i++)
                res=max(res,up[i]^k);
        } else {
            int l=1,r=dt;
            while (r-l>2){
                int ll=l+(r-l)/3;
                int rr=r-(r-l)/3;
                if ((dw[ll]^k)<(dw[rr]^k))
                    l=ll; else r=rr;
            }
            for (int i=l;i<=r;i++)
                res=max(res,dw[i]^k);
        }
        return res;
    }
}tree[N];

LL query(int rt,int l,int r,int ll,int rr,point k){
    if (ll<=l && r<=rr){
        if (!v[rt]) tree[rt].gao(l,r);
        v[rt]=1;return tree[rt].query(k);
    }
    int mid=(l+r)>>1;LL res=-inf;
    if (ll<=mid) res=max(res,query(2*rt,l,mid,ll,rr,k));
    if (rr> mid) res=max(res,query(2*rt+1,mid+1,r,ll,rr,k));
    return res;
}

int read(){  
    int res=0,f=1;char c=getchar();  
    while(!isdigit(c))f=f==-1||c=='-'?-1:1,c=getchar();  
    while(isdigit(c))res=res*10+c-'0',c=getchar();  
    return (res*f);  
} 

int gao(){return lastans&0x7fffffff;}
int main(){
    freopen("a.in","r",stdin);
    scanf("%d%s",&m,s);
    for (int i=1;i<=m;i++){
        scanf("%s",tt);
        if (tt[0]=='A'){
            x=read();y=read();
            g[i].x=x;g[i].y=y;
            g[i].op=1;n++;
        } else {
            x=read();y=read();
            l=read();r=read();
            g[i].x=x;g[i].y=y;
            g[i].l=l;g[i].r=r;
            g[i].op=2;
        }
    }
    for (int i=1;i<=m;i++){
        if (g[i].op==1){
            x=g[i].x;y=g[i].y;
            if (s[0]!='E'){
                x^=gao();y^=gao();
            }
            p[++size]=point(x,y);
        } else {
            x=g[i].x;y=g[i].y;
            l=g[i].l;r=g[i].r;
            if (s[0]!='E'){
                x^=gao();y^=gao();
                l^=gao();r^=gao();
            }
            lastans=query(1,1,n,l,r,point(x,y));
            printf("%lld\n",lastans);
        }
    }
}

bzoj1857

三分套三分~就是分別三分兩線段。
證明:http://blog.csdn.net/geotcbrl/article/details/48833339

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>

using namespace std;
double p,q,len,ans;
const double eps=0.00000001;
struct node{
    double x,y;
    node(){}
    node(double _x,double _y):x(_x),y(_y){}
    friend double dis(node a,node b){
        return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
    }
    friend node operator - (node a,node b){
        return node(a.x-b.x,a.y-b.y);
    }
    friend node operator + (node a,node b){
        return node(a.x+b.x,a.y+b.y);
    }
    friend node operator / (node a,double x){
        return node(a.x/x,a.y/x);
    }
}a,b,c,d;

double find(node a){
    node l=c,r=d;
    double res=min(dis(a,r)/len,(dis(a,l)+dis(l,r))/len);
    while (dis(l,r)>eps){
        node ll=l+(r-l)/3.0;
        node rr=r-(r-l)/3.0;
        double t1=dis(d,ll)/q,t2=dis(d,rr)/q;
        t1+=dis(ll,a)/len,t2+=dis(rr,a)/len;
        if (t1<t2) 
            res=min(res,t1),r=rr; else
            res=min(res,t2),l=ll;
    }
    return res;
}

int main(){
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    scanf("%lf%lf%lf%lf",&a.x,&a.y,&b.x,&b.y);
    scanf("%lf%lf%lf%lf",&c.x,&c.y,&d.x,&d.y);
    scanf("%lf%lf%lf",&p,&q,&len);
    node l=a,r=b;ans=min(find(a),dis(l,r)/p+find(b));
    while (dis(l,r)>eps){
        node ll=l+(r-l)/3.0;
        node rr=r-(r-l)/3.0;
        double t1=dis(a,ll)/p,t2=dis(a,rr)/p;
        double r1=find(ll),r2=find(rr);
        r1+=t1;r2+=t2;
        if (r1<r2)
            ans=min(ans,r1),r=rr; else
            ans=min(ans,r2),l=ll;
    }
    printf("%.2lf\n",ans);
}

bzoj1229

若天數少的話就可以用費用流水掉了。
不然就貪心亂搞。
顯然能去慢洗肯定比去快洗好(快洗比慢洗貴)。
現在問題來了,我們究竟要多少玩具捏。三分一波一開始的玩具個數(不會證明)然後在貪心亂搞一下就好了。

int gao(int x){
    sl.clear();qk.clear();tm.clear();
    int res=x*(tc-c2);
    sl.push_back(node(0,x));
    for (int i=1;i<=d;i++){
        while (!tm.empty() && i-tm.front().x>=n1)
            qk.push_back(tm.front()),tm.pop_front();
        while (!qk.empty() && i-qk.front().x>=n2)
            sl.push_back(qk.front()),qk.pop_front();
        int T=t[i];
        while (T){
            if (!sl.empty()){
                if (sl.back().c>=T){
                    sl.back().c-=T;
                    res+=T*c2;T=0;
                } else {
                    T-=sl.back().c;
                    res+=sl.back().c*c2;
                    sl.pop_back();
                }
            } else
            if (!qk.empty()){
                if (qk.back().c>=T){
                    qk.back().c-=T;
                    res+=T*c1;T=0;
                } else {
                    T-=qk.back().c;
                    res+=qk.back().c*c1;
                    qk.pop_back();
                }
            } else return inf;
        }
        tm.push_back(node(i,t[i]));
    }
    return res;
}
發佈了193 篇原創文章 · 獲贊 9 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章