标签:影响 getchar break tin namespace amp 最小生成树 push 离散化
T1T2分往脸上送,T3直接劝退。
数三角形。
先固定一条直线,求它能与其他直线组成多少个三角形。这个很好求。
令 \(S\) 为所有直线的集合,\(k_i\) 表示直线 \(i\) 的斜率,\(c_k\) 表示斜率为 \(k\) 的直线条数,则直线 \(l\) 能与其他直线组成的三角形个数即为:
将斜率离散化,预处理出 \(\sum_{i\in S}c_{k_i}^2\) ,枚举 \(l\) 。
因为最后每个三角形都会被计算 \(3\) 次,所以最后答案还要除以 \(3\) 。
\(\text{Code}:\)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=3e5+5;
typedef long long lxl;
template <typename T>
inline void read(T &x)
{
x=0;T f=1;char ch=getchar();
while(ch<‘0‘||ch>‘9‘) {if(ch==‘-‘) f=-1;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘) {x=(x<<1)+(x<<3)+ch-‘0‘;ch=getchar();}
x*=f;
}
int n;
double k[maxn],b[maxn];
int a[maxn];
lxl cnt[maxn],sum;
int main()
{
// freopen("trokuti.in","r",stdin);
// freopen("trokuti.out","w",stdout);
read(n);
for(int i=1,A,B,C;i<=n;++i)
{
read(A),read(B),read(C);
if(!B) k[i]=b[i]=1e9+1;
else k[i]=b[i]=-(double)A/B;
}
sort(b+1,b+n+1);
int m=unique(b+1,b+n+1)-b-1;
for(int i=1;i<=n;++i)
{
a[i]=lower_bound(b+1,b+m+1,k[i])-b;
++cnt[a[i]];
}
for(int i=1;i<=m;++i)
sum+=cnt[i]*cnt[i];
lxl ans=0;
for(int i=1;i<=n;++i)
ans+=1ll*((n-cnt[a[i]])*(n-cnt[a[i]])-(sum-cnt[a[i]]*cnt[a[i]]));
printf("%lld\n",ans/6ll);
return 0;
}
用平衡树模拟进站过程,每次找到队尾元素编号大于进站编号的队列中队尾元素编号最小的队列,进入这个队列,若不存在这样的队列,则进入一个新的队列。
因为只有队尾的元素会产生影响,所以只需要保存队尾元素编号即可。支持查询前驱和单点修改,使用平衡树即可。
\(\text{Code}:\)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <ctime>
#include <climits>
using namespace std;
const int maxn=1e5+5;
template <typename T>
inline void read(T &x)
{
x=0;T f=1;char ch=getchar();
while(ch<‘0‘||ch>‘9‘) {if(ch==‘-‘) f=-1;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘) {x=(x<<1)+(x<<3)+ch-‘0‘;ch=getchar();}
x*=f;
}
int n;
struct node
{
int siz,val;
node *ls,*rs;
node(int siz,int val,node *ls,node *rs):siz(siz),val(val),ls(ls),rs(rs){}
node(){}
}*root,*null,*st[maxn<<2],tt[maxn<<2];
const int ratio=4;
int cnt;
#define new_node(a,b,c,d) (&(*st[cnt++]=node(a,b,c,d)))
#define merge(a,b) new_node(a->siz+b->siz,b->val,a,b)
inline void update(node *p)
{
if(!p->ls->siz) return;
p->siz=p->ls->siz+p->rs->siz;
p->val=p->rs->val;
}
inline void rotate(node *p)
{
if(p->ls->siz > p->rs->siz*ratio)
p->rs=merge(p->ls->rs,p->rs),st[--cnt]=p->ls,p->ls=p->ls->ls;
if(p->rs->siz > p->ls->siz*ratio)
p->ls=merge(p->ls,p->rs->ls),st[--cnt]=p->rs,p->rs=p->rs->rs;
}
void insert(node *p,int d)
{
if(p->siz==1)
{
p->ls=new_node(1,min(p->val,d),null,null);
p->rs=new_node(1,max(p->val,d),null,null);
}
else insert(p->ls->val>=d ? p->ls : p->rs,d);
update(p);rotate(p);
}
void erase(node *p,int d)
{
if(p->ls->siz==1&&p->ls->val==d)
st[--cnt]=p->ls,st[--cnt]=p->rs,*p=*p->rs;
else if(p->rs->siz==1&&p->rs->val==d)
st[--cnt]=p->ls,st[--cnt]=p->rs,*p=*p->ls;
else erase(p->ls->val>=d ? p->ls : p->rs,d);
update(p);rotate(p);
}
int kth(node *p,int k)
{
if(p->siz==1) return p->val;
return p->ls->siz>=k ? kth(p->ls,k) : kth(p->rs,k-p->ls->siz);
}
int rnk(node *p,int d)
{
if(p->siz==1) return 1;
return p->ls->val>=d ? rnk(p->ls,d) : p->ls->siz+rnk(p->rs,d);
}
int nxt(int d) {return kth(root,rnk(root,d+1));}
void print(node *p)
{
if(p->siz==1) printf("%d ",p->val);
else print(p->ls),print(p->rs);
}
inline void init()
{
null=new node(0,0,0,0);
for(int i=0;i<=(maxn<<1);++i) st[i]=&tt[i];
root=new_node(1,INT_MAX,null,null);
}
int main()
{
// freopen("manage.in","r",stdin);
// freopen("manage.out","w",stdout);
read(n);
init();
for(int i=1,p;i<=n;++i)
{
read(p);
int x=nxt(p);
if(x==INT_MAX)
insert(root,p);
else
{
erase(root,x);
insert(root,p);
}
// print(root);puts("");
}
printf("%d\n",root->siz-1);
return 0;
}
这题我人都傻了,题解还没有证明它的正确性……
考场上写了个随机化算法拿了10pt/kk。
题解:
至于为什么这样做是对的,打死出题人就知道了 。
\(\text{Code}:\)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
#include <climits>
#define Rint register int
#define INF 0x3f3f3f3f
using namespace std;
typedef long long lxl;
const int maxn=405,maxm=5e4+5;
template <typename T>
inline void read(T &x)
{
x=0;T f=1;char ch=getchar();
while(ch<‘0‘||ch>‘9‘) {if(ch==‘-‘) f=-1;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘) {x=(x<<1)+(x<<3)+ch-‘0‘;ch=getchar();}
x*=f;
}
struct edge
{
int u,v;
lxl g,s;
edge(int u,int v,lxl g,lxl s):u(u),v(v),g(g),s(s){}
edge(){}
}e[maxm];
inline bool cmp_g(const edge &a,const edge &b)
{
return a.g<b.g;
}
inline bool cmp_s(const edge &a,const edge &b)
{
return a.s<b.s;
}
int n,m;
int fa[maxn];
lxl wG,wS;
int find(int x) {return fa[x]==x?x:fa[x]=find(fa[x]);}
inline lxl Kruskal(vector<edge> &S,vector<edge> &T)
{
for(int i=1;i<=n;++i) fa[i]=i;
T.clear();
sort(S.begin(), S.end(),cmp_s);
int cnt=0;
lxl MaxG=0,MaxS=0;
for(auto e:S)
{
int u=e.u,v=e.v;
int x=find(u),y=find(v);
if(x==y) continue;
MaxG=max(MaxG,e.g);
MaxS=max(MaxS,e.s);
fa[x]=y;
T.push_back(e);
++cnt;
if(cnt==n-1) break;
}
return cnt==n-1?MaxG+MaxS:LLONG_MAX;
}
vector<edge> vec[2];
int main()
{
// freopen("road.in","r",stdin);
read(n),read(m);
read(wG),read(wS);
int u,v;lxl g,s;
for(int i=1;i<=m;++i)
{
read(u),read(v),read(g),read(s);
e[i]=edge(u,v,g*wG,s*wS);
}
sort(e+1,e+m+1,cmp_g);
lxl ans=LLONG_MAX;
for(int i=1;i<=m;++i)
{
int id=i&1;
vec[id].push_back(e[i]);
ans=min(ans,Kruskal(vec[id],vec[id^1]));
}
printf("%lld\n",ans);
return 0;
}
标签:影响 getchar break tin namespace amp 最小生成树 push 离散化
原文地址:https://www.cnblogs.com/syc233/p/13803500.html